Spring + SpringMVC + Druid + JPA(Hibernate impl) 給你一個穩妥的後端解決方案

来源:http://www.cnblogs.com/java-class/archive/2016/10/12/5951738.html
-Advertisement-
Play Games

最近手頭的工作不太繁重,自己試著倒騰了一套用開源框架組建的 JavaWeb 後端解決方案。 感覺還不錯的樣子,但實踐和項目實戰還是有很大的落差,這裡只做拋磚引玉之用。 項目 git 地址:https://git.oschina.net/LanboEx/sdh.git 大體採用的開源項目有:Sprin ...


   最近手頭的工作不太繁重,自己試著倒騰了一套用開源框架組建的 JavaWeb 後端解決方案。

   感覺還不錯的樣子,但實踐和項目實戰還是有很大的落差,這裡只做拋磚引玉之用。

   項目 git 地址:https://git.oschina.net/LanboEx/sdh.git

   大體採用的開源項目有:Spring + SpringMVC + Druid + JPA(Hibernate Impl)。

1. 採用到的開源項目漫談

   Spring 迷人的依賴註入特性, 使其已經穩穩的占據在 JavaEE 項目引用開源項目列表中的上層位置。

   秉承低耦合高內聚的遵旨, Spring 提倡的對象工廠解耦類關係的思想已深入到每個攻城獅的心中。

   SpringMVC 做為 Spring 的乾兒子,最讓我沉醉的是她強大的擴展能力,深邃的像大海一樣。

   前端無論是 freemarker/velocity/jsp...,後端 DAO 層無論是傳統的 ORM 還是新近上位的領域模型。

   她的態度始終如一,給你360度最貼心的呵護,有一人對你如此,此生足矣。

   官網地址:http://projects.spring.io/spring-framework/

   項目中關於 SpringMVC + Spring 的依賴:

       <!--spring mvc-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>4.3.3.RELEASE</version>
        </dependency>

        <!-- Spring-orm -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-orm</artifactId>
            <version>4.3.3.RELEASE</version>
        </dependency>

        <!-- Spring AOP 動態代理 -->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.8.9</version>
        </dependency>

   這上面我想說的是 AspectJ 這個東東, AspectJ 是最早、功能比較強大的 AOP 實現之一。

   在 Java 領域,AspectJ 中的很多語法結構基本上已成為 AOP 領域的標準。

   Spring 也有自己的 Spring-AOP,Spring-AOP 採用運行時生成代理類,底層可以選用 JDK 或者 CGLIB 動態代理。

   通俗點,AspectJ 在編譯時增強要切入的類,而 Spring-AOP 是在運行時通過代理類增強切入的類,效率和性能可想而知。

   所以 Spring 在 2.0 的時候就已經開始支持 AspectJ ,現在到 4.X 的時代已經很完美的和 AspectJ  結合到一起。

   有興趣的可以在接著讀讀:https://www.oschina.net/translate/comparative_analysis_between_spring_aop_and_aspectj?cmp

   Druid 出自阿裡巴巴技術團隊之手,個人認為是比較好的資料庫連接池之一,尤其是監控部分是我的最愛。

   官方 github 地址:https://github.com/alibaba/druid/wiki/常見問題

   項目中的 web.xml 配置監控配置和監控界面:

   <!--Druid 資料庫連接池監控-->
    <servlet>
        <servlet-name>DruidStatView</servlet-name>
        <servlet-class>com.alibaba.druid.support.http.StatViewServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>DruidStatView</servlet-name>
        <url-pattern>/druid/*</url-pattern>
    </servlet-mapping>

 

 

   JPA 作為 Sun 公司引入的 ORM 規範,就像是 JDBC 之於各種資料庫驅動 Jar,

   不要去在意使用了什麼樣的資料庫,用 JDBC 提供的規範方法去擼代碼即可。

   JPA 制定持久層規範,相同與抽象介面,有 ORM 框架擼具體的實現層。

   Sun 想實現 ORM 技術統一,可能不遠的將來,你不用在糾結選擇什麼樣子的 ORM 框架。

   而現有熱門的 ORM 框架會漸漸失去光澤,這畢竟是個漫長的過程,讓我們拭目以待。

2. 方案整體一覽

   方案中所有的類都位於 SpringContext 中,由 Spring 統一進行管理。

   讓 Spring 統一管理的前提是你要告訴有這樣一個類需要它管理,目前我接觸到的告訴途徑有兩種。

   傳統的 xml 配置和註解方式,xml 配置和註解方式各有優劣,比如 xml 配置的優點:

   a. 如果你公司項目在引用另外一個公司的 jar,這時候,唯一可行方式為 xml 配置。

   b. 如果類之間的依賴關係變動頻繁,xml 配置是比較優秀的,改動代碼和改動配置文件,無論是技術上還是風險上,xml 都穩贏註解。

   註解聲明的方式優點:代碼和聲明在一起,開發的時候不用切來切去,比 xml 配置聲明要簡單明瞭的多。

   現在很多主流的框架都引入了註解,但也無法擯棄 xml 配置聲明的方式。

   

   在這個方案中我使用乾凈簡單註解的方式,controller 包下使用註解@controller,dao-impl 包下使用@Repository,service 包下使用@service。

  控制層註入服務實例,服務層註入數據訪問層對象,持久層對象由 JAP 進行註解,頁面通過控制層來傳輸和獲取數據。

  web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
          http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
         version="3.0">
    <!--Spring mvc -->
    <servlet>
        <servlet-name>springMVC</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>
                classpath:spring-mvc-base.xml
                classpath:spring-mvc-beans.xml
                classpath:spring-hibernate-beans.xml
            </param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
        <async-supported>true</async-supported>
    </servlet>

    <servlet-mapping>
        <servlet-name>springMVC</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>

    <!--Druid 資料庫連接池監控-->
    <servlet>
        <servlet-name>DruidStatView</servlet-name>
        <servlet-class>com.alibaba.druid.support.http.StatViewServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>DruidStatView</servlet-name>
        <url-pattern>/druid/*</url-pattern>
    </servlet-mapping>
</web-app>
View Code

  maven pom.xml:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.rambo</groupId>
    <artifactId>sdh</artifactId>
    <packaging>war</packaging>
    <version>1.0-SNAPSHOT</version>
    <name>sdh</name>
    <description>spring mvc + Druid + hibernate</description>

    <dependencies>
        <!--spring mvc-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>4.3.3.RELEASE</version>
        </dependency>

        <!-- Spring-orm -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-orm</artifactId>
            <version>4.3.3.RELEASE</version>
        </dependency>

        <!-- Spring AOP 動態代理 -->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.8.9</version>
        </dependency>

        <!-- Hibernate-core -->
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-core</artifactId>
            <version>4.3.1.Final</version>
        </dependency>

        <!-- Druid -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.0.26</version>
        </dependency>

        <!--mysql 數據驅動-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.38</version>
        </dependency>

        <!--日誌-->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version><!--2012.05 最後版本-->
        </dependency>
    </dependencies>
    <build>
        <finalName>sdh</finalName>
        <plugins>
            <plugin>
                <groupId>org.eclipse.jetty</groupId>
                <artifactId>jetty-maven-plugin</artifactId>
                <version>9.2.11.v20150529</version>
                <configuration>
                    <jvmArgs>-XX:PermSize=256M -XX:MaxPermSize=1024M</jvmArgs>
                    <webApp>
                        <contextPath>/${project.name}</contextPath>
                    </webApp>
                    <httpConnector>
                        <port>4040</port>
                    </httpConnector>
                    <stopKey>foo</stopKey>
                    <stopPort>9998</stopPort>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>
View Code

3. DAO 層的種種設計思路

   controller 和 service 層非常容易理解,就是不贅述了。

   DAO 層中 BasePo 和 是希望將一些共有的屬性抽象在父類當中(屬性由具體項目需求決定)。

@MappedSuperclass
public class BasePO implements Serializable {
    @Id
    @Column(length = 32, nullable = true)
    @GeneratedValue(generator = "uuid")
    @GenericGenerator(name = "uuid", strategy = "uuid")
    private String uuid;

    @Column(updatable = false)
    private Date createDate;

    private Date modifyDate;

    ....getter/setter
}
BasePO

   BaseDaoImpl 希望將一些公共的數據訪問方法實現在父類當中(我這裡的方法可能有點少,可以由具體項目增加)。

@Repository
public class BaseDaoImpl<T, PK extends Serializable> implements BaseDao<T, PK> {

    private Class<T> entityClass;
    @Resource
    protected SessionFactory sessionFactory;

    public BaseDaoImpl() {
        this.entityClass = null;
        Class<?> c = getClass();
        Type type = c.getGenericSuperclass(); //反射獲取超類
        if (type instanceof ParameterizedType) {
            Type[] parameterizedType = ((ParameterizedType) type).getActualTypeArguments();
            this.entityClass = (Class<T>) parameterizedType[0];
        }
    }

    protected Session getSession() {
        return sessionFactory.getCurrentSession();
    }

    public T getByKey(PK id) {
        Assert.notNull(id, "id is required");
        return (T) getSession().get(entityClass, id);
    }

    public T add(T entity) {
        Assert.notNull(entity, "entity is required");
        getSession().save(entity);
        return entity;
    }

    public T edit(T entity) {
        Assert.notNull(entity, "entity is required");
        getSession().update(entity);
        return entity;
    }

    public T deleteByKey(PK id) {
        Assert.notNull(id, "id is required");
        T t = (T) getSession().load(entityClass, id);
        getSession().delete(t);
        return t;
    }
}
BaseDaoImpl

   使用 JAP 註解編寫業務使用到的持久層對象。

@Entity
@Table(name = "t_user")
public class User extends BasePO {
    @Column(nullable = false)
    String name;
    @Column(nullable = false)
    String pwd;
....getter/setter }

   配置啟動時掃描 POJO 的動作,至於是新建還是更新都有配置選項,可以自己查閱相關文檔。

    <!-- 配置hibernate session工廠,需添加 spring-orm -->
    <bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop>
                <prop key="hibernate.dialect">${hibernate.dialect}</prop>
                <prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
                <prop key="hibernate.format_sql">${hibernate.format_sql}</prop>
            </props>
        </property>

        <!-- 自動掃描註解方式配置的hibernate類文件 -->
        <property name="packagesToScan">
            <list>
                <value>com.rambo.sdh.pojo</value>
            </list>
        </property>
    </bean>

   操縱資料庫最主要的事務管理,採用 AOP 聲明方式,在執行含有數據變動的方法前後進行攔截。

   採用 AOP 聲明方式進行攔截的好處,不用去關註資料庫事務的開啟和關閉,將重心放到業務邏輯上面。

<!-- 配置事務管理器 -->
    <bean name="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory"/>
    </bean>

    <!-- 聲明式容器事務管理 ,transaction-manager指定事務管理器為transactionManager- -->
    <tx:advice id="transactionAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="add*"/>
            <tx:method name="save*"/>
            <tx:method name="update*"/>
            <tx:method name="modify*"/>
            <tx:method name="edit*"/>
            <tx:method name="delete*"/>
            <tx:method name="remove*"/>
            <tx:method name="repair"/>
            <tx:method name="deleteAndRepair"/>

            <tx:method name="get*" propagation="SUPPORTS"/>
            <tx:method name="find*" propagation="SUPPORTS"/>
            <tx:method name="load*" propagation="SUPPORTS"/>
            <tx:method name="search*" propagation="SUPPORTS"/>
            <tx:method name="datagrid*" propagation="SUPPORTS"/>
            <tx:method name="*" propagation="SUPPORTS"/>
        </tx:attributes>
    </tx:advice>
    <aop:config>
        <aop:pointcut id="transactionPointcut" expression="execution(* com.rambo.sdh.service..*Impl.*(..))"/>
        <aop:advisor pointcut-ref="transactionPointcut" advice-ref="transactionAdvice"/>
    </aop:config>

   上面配置文件的大體意思是說,在包 com.rambo.sdh.service..*Impl.* 下所執行的已 add/save/update.....開頭的方法。

   方法在執行前後都會被 HibernateTransactionManager 攔截住,進行事務的開啟和關閉。

   當然還有一些其他的事情,有興趣可以 debug 源碼去一探究竟。

   貌似說的也差不多了,該方案為 javaweb 後端解決方案,前端用你想用的渲染技術即可。

   項目開源 GIT 地址已在最上面給出,如果有興趣的可以檢出到本地跑一跑,該方案中小公司其實都挺適合,上手和開發速度快。

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 1、介紹 vs15是微軟打造的新一代IDE,全新的安裝方式。官網介紹如下(https://blogs.msdn.microsoft.com/visualstudio/2016/10/05/announcing-visual-studio-15-preview-5/): 據微軟描述,Preview 5... ...
  • CUP和.NET SQL版本不同也會存在少許差距,但不會有質變,下麵的測試結果僅供參考 比賽規則 1.統一使用Realse版本的最新 DLL,Realse模式啟用程式 2.為了平衡CPU和資料庫空閑情況,使用車輪戰,每場比賽連續10回合比試 3.多次重啟電腦取平均成績上圖 比賽成員 1.SqlSug ...
  • 目錄 1.簡介... 2 2.適用範圍... 2 3.規範目的... 2 4.代碼組織與風格... 2 4.1 Tab鍵... 2 4.2 縮進... 3 4.3空行... 3 4.4函數長度... 3 4.5行寬... 3 4.6{ “,”} 3 5.文件命名... 3 6.命名... 4 6.1 ...
  • 什麼是ORM? 對象關係映射(英語:Object Relation Mapping,簡稱ORM,或O/RM,或O/R mapping),是一種程式技術,用於實現面向對象編程語言里不同類型系統的數據之間的轉換。從效果上說,它其實是創建了一個可在編程語言里使用的“虛擬對象資料庫”。 一般的ORM包括以下 ...
  • 前兩天朋友問我,有沒有使用過StackExchange.Redis,問我要個封裝類,由於之前都是使用ServiceStack.Redis,由於ServiceStack.Redis v4版本後是收費版的,所以現在也很有公司都在使用StackExchange.Redis而拋棄ServiceStack.R ...
  • ASP.NET Core請求處理管道由一個伺服器和一組中間件構成。如果想非常深刻地認識ASP.NET Core的請求處理管道,我覺得可以分兩個步驟來進行:首先,我們可以在忽略具體細節的前提下搞清楚管道處理HTTP請求的總體流程;在對總體流程有了大致瞭解之後,我們再來補充這些刻意忽略的細節。為了讓讀者... ...
  • 摘要:任何語言開發出來的程式,都會有一個程式入口函數,可能每個語言所使用的程式入口函數名稱不一樣,但是它們的作用都是一樣的,都是被操作系統去調用。那麼本文主要總結.NET中的程式入口函數Main使用的小技巧。 引言 最近在使用pandoc這個文檔轉換軟體,能夠對各種文檔進行完美的轉換,比如從mark ...
  • 絕對佈局Absolute 通過放大或縮小界面的時候,組件大小和位置不會發生變化 浮動佈局FlowLayout 調整應用程式視窗的大小時,組件將立刻重新排列 邊界佈局Border Layout 該位置有5個方位:東、南、西、北、中 網格佈局Grid Layout 如需要將大量組件按規律排列,那麼網格布 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...