MAVEN整合Spring+SpringMVC+Mybatis

2016/1/20 14:47:28


原創,轉載請註明出處

曾經看過《那些年我們一起追過的女孩》,片中有個比較經典的畫面,至今記憶猶新,柯景騰多年後,做了一名作家,每天面對電腦碼字,背後是一張張一閃而過的字幅“人生就是不停的戰鬥”

作爲程序員,我想一生就是不停的和BUG做戰鬥了,新來的這家公司,用的很老的Spring+Struts2.0+JDBC的框架,非常的不好用,其中的問題可以陳述10條以上,但是限於當時的技術水平所限,不能達到也很正常,所以我萌生了一個推翻重寫後臺的想法(從這到正文部分純屬裝逼的,大神繞過,新人還是需要看一哈,熟悉一下爲什麼是MAVEN)

JAVA這門語言,之前看一個漫畫是這麼形容的,C++是加農炮,威力強大,什麼都能炸;JAVA是一個手機,它能打電話叫來各種炮,炸的你爹媽不認得,但是它的JAR存在着依賴關係,比如Spring中的對AspectJ和JSR的支持是基於AspectJ和其他的JAR包的,你用它之前必須要先有依賴的jar包;項目中有兩個典型的jar就是如此

  • aopalliance-1.0.jar 它是SpringAOP的基礎依賴包
  • hamcrest-core-1.1.jar 他是Junit依賴的jar包

那麼問題來了,我要是打電話,請人幫我“炸樓”,就好比JAVA請JAR包,我是不是連它爸媽一起請?我是不是要配置所有的依賴包,答案NO,因爲我可以藉助MAVEN這個神器啊,它會自動解析包的依賴關係去自動下載

在這個項目的搭建和第一次用maven沒有人幫助我的情況下,能做出來還是有些小激動,也學習到了很多新的知識,重新把Spring學習了一遍,進一步理解了XML配置文件,SpringIOC和SpringAOP,驚歎於Spring框架的神奇之處,自己也掌握了許多Spring相關的技術,例如:Spring是支持JSON的,我們可以直接在控制層方法加@ResponseBody,可以自動返回JSON對象,So Easy

本文作者所用:所有東西的版本

  • MyEClipse GA 2014
  • Spring 4.2.4(最新)
  • Mybatis 3.3.0(最新)

參考博客

http://blog.csdn.net/zhshulin/article/details/37956105
http://blog.csdn.net/l349440843/article/details/45788017
http://blog.csdn.net/zhshulin/article/details/37937365

本文主要介紹的技術:(大神繞過)

  1. MAVEN搭建JAVA-WEB項目
  2. Spring的配置文件
  3. Junit單元測試
  4. Spring整合JSON輸出
  5. Spring整合Mybatis不需要寫DAO層代碼
  6. Log4j控制輸出,主要介紹擴展方式寫日誌進數據庫的方式
  7. 代碼註釋的規範,和一些MyEclipse的規範操作(個人覺得規範的)

作爲程序界的老鳥,看到這篇文章就自動過濾之前這一段,不過本作也真誠的希望你們能爲我提出建議,謝謝,言歸正傳,開始操練

1.MAVEN

  • Maven是基於項目對象模型(POM),可以通過一小段描述信息來管理項目的構建,報告和文檔的軟件項目管理工具。
  • Maven 除了以程序構建能力爲特色之外,還提供高級項目管理工具。由於 Maven 的缺省構建規則有較高的可重用性,所以常常用兩三行 Maven 構建腳本就可以構建簡單的項目。由於 Maven 的面向項目的方法,許多 Apache Jakarta 項目發文時使用 Maven,而且公司項目採用 Maven 的比例在持續增長。
  • 用MAVEN來管理jar包,不用一個一個去添加和下載jar包了,直接在maven配置文件中配置就可以了,maven可以幫助我們自動下載

1.1首先搭建一個maven項目

第一次新建MAVEN項目的筒子,你們在這裏要稍微等一哈,MAVEN要去下載依賴

WEB項目點中上面的maven-archetype-webapp點擊下一步


Group Id一般填公司的包名吧,第二個填公司名,其實我也不是很懂這個= =好像沒有多大用

然後MAVEN就開始在US鏡像倉庫下載包和一些準備工作了你的MyEclipse的右下角,就會出現

至此,你的MAVEN項目就初步搭建好了

1.2那麼接下來怎麼搞

搭建好的MAVEN項目如下圖

問題有兩個,一個我,作爲一個高逼格的程序員,一定要用最新版本的JRE環境,所以把項目構建改到最高版本,另外,報了一個 “javax.servlet.http.HttpServlet” was not found on the Java Build Path index.jsp錯誤,這是由於在index.jsp頁面上缺少對JavaEE的支持,因此需要添加JavaEE的類庫

  1. 右鍵工程–>properties–>JAVA Build Path–>Edit
  2. 在pox.xml中添加對JAVA EE的依賴

1.3最後是pom.xml的配置

如果遇到環境配置的問題,可以參考博文:MyEclipse+Tomcat+MAVEN+SVN項目完整環境搭建

點開pom.xml配置你的項目maven依賴,坐等幾分鐘,maven會下載JAR,如果不下載,或者停止,就點開MyEclipse 找到 MAVEN4MyEclipse 把下載按鈕打開,或者還原爲默認的

<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.zjx</groupId>
  <artifactId>zjx</artifactId>
  <packaging>war</packaging>
  <version>0.0.1-SNAPSHOT</version>
  <name>zjx Maven Webapp</name>
  <url>http://maven.apache.org</url>

  <properties>  
        <!-- spring版本號 -->  
        <spring.version>4.2.4.RELEASE</spring.version>  
        <!-- mybatis版本號 -->  
        <mybatis.version>3.3.0</mybatis.version>  
        <!-- log4j日誌文件管理包版本 -->  
        <slf4j.version>1.7.7</slf4j.version>
        <log4j.version>1.2.16</log4j.version>   
    </properties>

  <dependencies>

    <!-- 單元測試的依賴 --> 
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.10</version>
      <scope>test</scope>
    </dependency>   



        <!-- spring核心包 -->  
        <dependency>  
            <groupId>org.springframework</groupId>  
            <artifactId>spring-core</artifactId>  
            <version>${spring.version}</version>  
        </dependency> 

        <!-- spring對web的支持 -->  
        <dependency>  
            <groupId>org.springframework</groupId>  
            <artifactId>spring-web</artifactId>  
            <version>${spring.version}</version>  
        </dependency> 

        <!-- spring對ORM映射的支持-->   
        <dependency>  
            <groupId>org.springframework</groupId>  
            <artifactId>spring-oxm</artifactId>  
            <version>${spring.version}</version>  
        </dependency> 

        <!-- spring事務管理支持 -->   
        <dependency>  
            <groupId>org.springframework</groupId>  
            <artifactId>spring-tx</artifactId>  
            <version>${spring.version}</version>  
        </dependency>  

        <!-- spring對JDBC的支持 -->  
        <dependency>  
            <groupId>org.springframework</groupId>  
            <artifactId>spring-jdbc</artifactId>  
            <version>${spring.version}</version>  
        </dependency>  

        <!-- spring對MVC框架的支持 -->  
        <dependency>  
            <groupId>org.springframework</groupId>  
            <artifactId>spring-webmvc</artifactId>  
            <version>${spring.version}</version>  
        </dependency>  

        <!-- spring切面支持 -->  
        <dependency>  
            <groupId>org.springframework</groupId>  
            <artifactId>spring-aop</artifactId>  
            <version>${spring.version}</version>  
        </dependency>  

        <!-- spring上下文支持 -->  
        <dependency>  
            <groupId>org.springframework</groupId>  
            <artifactId>spring-context-support</artifactId>  
            <version>${spring.version}</version>  
        </dependency>  

        <!-- spring測試支持 -->  
        <dependency>  
            <groupId>org.springframework</groupId>  
            <artifactId>spring-test</artifactId>  
            <version>${spring.version}</version>  
        </dependency> 

        <!-- AspectJ支持 -->
        <dependency>
            <groupId>aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>1.5.4</version>
        </dependency> 
        <!-- 織入 -->
        <dependency>
            <groupId>aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.5.4</version>
        </dependency>

        <!-- mybatis核心包 -->  
        <dependency>  
            <groupId>org.mybatis</groupId>  
            <artifactId>mybatis</artifactId>  
            <version>${mybatis.version}</version>  
        </dependency>  
        <!-- mybatis對spring的支持 -->  
        <dependency>  
            <groupId>org.mybatis</groupId>  
            <artifactId>mybatis-spring</artifactId>  
            <version>1.2.3</version>  
        </dependency>  

        <!-- 導入Mysql數據庫鏈接jar包 -->  
        <dependency>  
            <groupId>mysql</groupId>  
            <artifactId>mysql-connector-java</artifactId>  
            <version>5.1.30</version>  
        </dependency> 

        <!-- 導入dbcp的jar包,用來在applicationContext.xml中配置數據庫 -->  
       <dependency>
            <groupId>commons-dbcp</groupId>
            <artifactId>commons-dbcp</artifactId>
            <version>1.4</version>
        </dependency>

        <!-- JSTL標籤類 -->  
        <dependency>  
            <groupId>jstl</groupId>  
            <artifactId>jstl</artifactId>  
            <version>1.2</version>  
        </dependency>  

        <!-- 日誌文件管理包 --> 

        <!-- log start --> 
        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.2</version>
        </dependency> 
        <dependency>  
            <groupId>log4j</groupId>  
            <artifactId>log4j</artifactId>  
            <version>${log4j.version}</version>  
        </dependency> 

        <!-- 格式化對象,方便輸出日誌 -->  
        <dependency>  
            <groupId>com.alibaba</groupId>  
            <artifactId>fastjson</artifactId>  
            <version>1.1.41</version>  
        </dependency> 

         <!-- 導入java ee jar 包 -->  
        <dependency>  
            <groupId>javax</groupId>  
            <artifactId>javaee-api</artifactId>  
            <version>7.0</version>  
        </dependency>  


        <dependency>  
            <groupId>org.slf4j</groupId>  
            <artifactId>slf4j-api</artifactId>  
            <version>${slf4j.version}</version>  
        </dependency>  

        <dependency>  
            <groupId>org.slf4j</groupId>  
            <artifactId>slf4j-log4j12</artifactId>  
            <version>${slf4j.version}</version>  
        </dependency>  


        <!-- log end -->

        <!-- 映入JSON支持 --> 

        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-annotations</artifactId>
            <version>2.5.1</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.5.1</version>
        </dependency> 
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-core</artifactId>
            <version>2.5.1</version>
        </dependency>



        <!-- 文件上傳 -->
        <dependency>  
            <groupId>commons-fileupload</groupId>  
            <artifactId>commons-fileupload</artifactId>  
            <version>1.3.1</version>  
        </dependency>  
        <dependency>  
            <groupId>commons-io</groupId>  
            <artifactId>commons-io</artifactId>  
            <version>2.4</version>  
        </dependency>  
        <dependency>  
            <groupId>commons-codec</groupId>  
            <artifactId>commons-codec</artifactId>  
            <version>1.9</version>  
        </dependency>  


  </dependencies>
  <build>
    <finalName>zjx</finalName>
  </build>

</project>

所有的依賴包,和作用都註釋清楚,至此,MAVEN的工作就完了,剩下的事情就是項目

2. Spring配置文件

首先,先幾個題外話,所有人都知道程序分離是爲了簡化,人們習慣上把複雜的事情分解爲若干個簡單的事情處理,這就體現的是分層思想,所以程序上纔有了MVC,纔有了三層架構

當人們認知事物的高度達到一定程度之後,就會抓住事物的核心問題,也就是程序設計上常說的問題域,那麼請看下面兩個故事:

讓時間回到2001年,地點是澳大利亞悉尼的Clarence Street有一家叫做Cirrus Technologies的公司,這是一家做J2EE企業級應用開發和諮詢的公司,在會議桌上一個小夥子和老闆正在進行着激烈的討論。
小夥子:”老闆,我總覺得開發的效率太低了,我用了EJB的Entity bean 1.1時,我總覺得我浪費了好多時間在處理Entity Bean的體系架構上,卻沒有花時間在覈心業務邏輯的開發上,而且CMP給我們的限制太多了”。
老闆:”Gavin,別傻了,EJB是業界的標準,也是最流行的技術,而且我們公司是IBM的合作伙伴。如果有問題,問題就是我們還沒有適應這樣的開發模式”。
小夥子:”不,我覺得肯定有更好的解決的方案。我們可以設計出比Entity Bean更好的方案”。
老闆:”哦,Gavin,我知道你很聰明,開發水平也不錯。但是開發這樣的系統太難了,而且你根本就沒有用SQL開發過任何數據庫系統。不要想這樣一個不現實的目標啦!”
小夥子皺了皺眉,說道:”不,我相信我有能力開發出這個系統。我的想法絕對是可行的。”
(注:以上場景純屬虛構,但至少以下內容完全屬實:Gavin King開發hibernate的動機有兩個:發現CMP太爛;贏得對老闆的爭執。Gavin King當時沒有任何用SQL開發數據庫的經驗,Gavin King開發hibernate的第一件事是去街上買了本SQL基礎的書)

也許Cirrus Technologies的老闆做夢也想不到兩年以後,這個小夥子開發出的那個產品會成爲全世界最流行的O/R Mapping工具,而那個對SQL和數據庫一竅不通的小夥子居然會成爲全世界J2EE數據庫解決方案的領導者。

這就是Gavin King,一個充滿激情、脾氣很倔、永不言敗的人。他的成就也許全世界搞Java的人都知道:他是hibernate的創始人;他是EJB 3.0的Entity bean specification的實際領導人(sun任命的領導人應該是Linda DeMichiel);他也是那本經典的書hibernate in action的作者;他也參加了XDoclet和Middlegen的開發;他在全世界各種著名的會議(TheServerSide Symposium等)進行演講和講座。

2010年這個項目由apache software foundation 遷移到了google code,並且改名爲MyBatis 。2013年11月遷移到Github。它的廣告語是“我們已經學習了SQL,爲什麼我們還要學習HQL”;

故事給我的感觸是,必須要學習新的技術,永遠做第一個吃螃蟹的人,因爲只有你知道了什麼框架,有什麼不足,你纔會去改進,纔會去發明新的框架,這也就是許多大牛,喜歡鑽研技術,自己寫框架,而不用別人現成的框架,小弟只是個渣渣,各位路過的大神勿噴,能指點我一二最好

不扯閒話:上配置(配置也體現了控制層和業務層分離的思想),因爲項目開發的主要問題域在於業務邏輯的處理上,而不在DAO代碼上,因此沒有寫DAO層,而交給Mybatis去自動控制,也體現了故事一種的思想,配置文檔截圖如下

  • applicationContext-action.xml 是專門配置持久層的
  • applicationContext-base.xml 是專門配置控制層的
  • jdbc.properties 是專門配置數據庫連接的,這樣配置提現分離和修改數據庫的作用
  • log4j.properties 是專門配置日誌輸出和日誌控制的
  • mybatis.cfg.xml 是爲了提供ORM映射的配置,其中只需要配置一個類的別名,mapper已經移交Spring管理,但是個人嫌寫類名麻煩,喜歡用別名
  • mybatis.cfg.xml 這個配置可以不要,看到有大神才用註解的方式,希望有大神路過不吝賜教

applicationContext-action.xml

<?xml version="1.0" encoding="UTF-8"?>


<beans  xmlns="http://www.springframework.org/schema/beans" 
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
        xmlns:p="http://www.springframework.org/schema/p" 
        xmlns:aop="http://www.springframework.org/schema/aop" 
        xmlns:tx="http://www.springframework.org/schema/tx" 
        xmlns:mvc="http://www.springframework.org/schema/mvc" 
        xmlns:context="http://www.springframework.org/schema/context" 
        xsi:schemaLocation="http://www.springframework.org/schema/beans
                            http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
                            http://www.springframework.org/schema/context
                            http://www.springframework.org/schema/context/spring-context-3.0.xsd 
                            http://www.springframework.org/schema/aop
                            http://www.springframework.org/schema/aop/spring-aop-3.0.xsd 
                            http://www.springframework.org/schema/tx
                            http://www.springframework.org/schema/tx/spring-tx-3.0.xsd 
                            http://www.springframework.org/schema/mvc
                            http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd"> 

    <!-- 自動掃描該包,使SpringMVC認爲包下用了@controller註解的類是控制器,控制器全部放在這個包下 -->  
    <context:component-scan base-package="com.zjx.action">
<!--  如果使用包含採用該配置       <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/> -->
<!--  如果使用過濾採用該配置   <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service"/> -->
    </context:component-scan>

     <!--避免IE執行AJAX時,返回JSON出現下載文件 -->  
    <bean id="mappingJacksonHttpMessageConverter"  
        class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">  
        <property name="supportedMediaTypes">  
            <list>  
                <!-- 設置返回的編碼和解析方式 -->
                <value>text/html;charset=UTF-8</value>  
            </list>  
        </property>  
    </bean>  
    <!-- 啓動SpringMVC的註解功能,完成請求和註解POJO的映射 -->  
    <bean  
        class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">  
        <property name="messageConverters">  
            <list>  
                <ref bean="mappingJacksonHttpMessageConverter" /> <!-- JSON轉換器 -->  
            </list>  
        </property>  
    </bean>  


    <!-- 定義跳轉的文件的前後綴 ,視圖模式配置-->  
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">  
        <!-- 這裏的配置我的理解是自動給後面action的方法return的字符串加上前綴和後綴,變成一個 可用的url地址 -->  
        <property name="prefix" value="/WEB-INF/jsp/" />  
        <property name="suffix" value=".jsp" />  
    </bean>  

    <!-- 配置文件上傳,如果沒有使用文件上傳可以不用配置,當然如果不配,那麼配置文件中也不必引入上傳組件包 -->  
    <bean id="multipartResolver"    
        class="org.springframework.web.multipart.commons.CommonsMultipartResolver">    
        <!-- 默認編碼 -->  
        <property name="defaultEncoding" value="utf-8" />    
        <!-- 文件大小最大值 -->  
        <property name="maxUploadSize" value="10485760000" />    
        <!-- 內存中的最大值 -->  
        <property name="maxInMemorySize" value="40960" />    
    </bean>   

</beans>

applicationContext-base.xml

<?xml version="1.0" encoding="UTF-8"?>


<beans  xmlns="http://www.springframework.org/schema/beans" 
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
        xmlns:p="http://www.springframework.org/schema/p" 
        xmlns:aop="http://www.springframework.org/schema/aop" 
        xmlns:tx="http://www.springframework.org/schema/tx" 
        xmlns:mvc="http://www.springframework.org/schema/mvc" 
        xmlns:context="http://www.springframework.org/schema/context" 
        xsi:schemaLocation="http://www.springframework.org/schema/beans
                            http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
                            http://www.springframework.org/schema/context
                            http://www.springframework.org/schema/context/spring-context-3.0.xsd 
                            http://www.springframework.org/schema/aop
                            http://www.springframework.org/schema/aop/spring-aop-3.0.xsd 
                            http://www.springframework.org/schema/tx
                            http://www.springframework.org/schema/tx/spring-tx-3.0.xsd 
                            http://www.springframework.org/schema/mvc
                            http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd"> 
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
    <!-- 自動掃描 -->  
    <context:component-scan base-package="com.zjx" />  

    <!-- 引入配置文件 -->  
    <bean id="propertyConfigurer"  
        class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">  
        <property name="location" value="classpath:jdbc.properties" />  
    </bean> 

    <!-- 配置數據源 -->
    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">  
        <property name="driverClassName" value="${jdbc.driver}" />  
        <property name="url" value="${jdbc.url}" />  
        <property name="username" value="${jdbc.username}" />  
        <property name="password" value="${jdbc.password}" />  
        <!-- 初始化連接大小 -->  
        <property name="initialSize" value="${jdbc.initialSize}"></property>  
        <!-- 連接池最大數量 -->  
        <property name="maxActive" value="${jdbc.maxActive}"></property>  
        <!-- 連接池最大空閒 -->  
        <property name="maxIdle" value="${jdbc.maxIdle}"></property>  
        <!-- 連接池最小空閒 -->  
        <property name="minIdle" value="${jdbc.minIdle}"></property>  
        <!-- 獲取連接最大等待時間 -->  
        <property name="maxWait" value="${jdbc.maxWait}"></property>  
    </bean>  

    <!-- spring和MyBatis整合-->  
    <bean id="sessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">  
        <property name="dataSource" ref="dataSource" />  

        <!-- 指明mybatis主配置文件路徑 -->
        <property name="configLocation" value="classpath:mybatis.cfg.xml"></property>
        <!-- 指明mybatis的映射位置 -->
        <property name="mapperLocations">
            <list>
                <value>classpath:orm/*.xml</value>
            </list>
        </property>
    </bean>

    <!-- 配置SqlSession模版類,SqlSessionTemplate是線程安全類 -->
    <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate" scope="prototype">
        <constructor-arg  ref="sessionFactory"></constructor-arg>       
    </bean>

    <!-- 事務管理器 -->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!-- 允許使用註解配置事務 -->
    <tx:annotation-driven transaction-manager="transactionManager"/> 

    <!-- 掃描spring註解類 -->
    <context:component-scan base-package="com.zjx">
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Service"/>
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>

</beans>

jdbc.properties

jdbc.driver=org.gjt.mm.mysql.Driver
#定義連接的URL地址,設置編碼集,允許多條SQL語句操作
jdbc.url=jdbc:mysql://localhost:3306/test?characterEncoding=utf-8&amp;allowMultiQueries=true
jdbc.username=root  
jdbc.password=82651205
#定義初始連接數  
jdbc.initialSize=10  
#定義最大連接數  
jdbc.maxActive=20  
#定義最大空閒  
jdbc.maxIdle=20  
#定義最小空閒  
jdbc.minIdle=10 
#定義最長等待時間  
jdbc.maxWait=60000  

log4j.properties

### direct log messages to stdout ###
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n

### direct messages to file hibernate.log ###
#log4j.appender.file=org.apache.log4j.FileAppender
#log4j.appender.file.File=hibernate.log
#log4j.appender.file.layout=org.apache.log4j.PatternLayout
#log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n

### set log levels - for more verbose logging change 'info' to 'debug' ###

log4j.rootLogger=warn, stdout

#log4j.logger.org.hibernate=info
#log4j.logger.org.hibernate=debug

### log HQL query parser activity
#log4j.logger.org.hibernate.hql.ast.AST=debug

### log just the SQL
#log4j.logger.org.hibernate.SQL=debug

### log JDBC bind parameters ###
#log4j.logger.org.hibernate.type=info
#log4j.logger.org.hibernate.type=debug

### log schema export/update ###
#log4j.logger.org.hibernate.tool.hbm2ddl=debug

### log HQL parse trees
#log4j.logger.org.hibernate.hql=debug

### log cache activity ###
#log4j.logger.org.hibernate.cache=debug

### log transaction activity
#log4j.logger.org.hibernate.transaction=debug

### log JDBC resource acquisition
#log4j.logger.org.hibernate.jdbc=debug

### enable the following line if you want to track down connection ###
### leakages when using DriverManagerConnectionProvider ###
#log4j.logger.org.hibernate.connection.DriverManagerConnectionProvider=trace

################################################################################
########文件記錄日誌的方式

##定義LOG輸出級別  
#log4j.rootLogger=INFO,Console,File  
##定義日誌輸出目的地爲控制檯  
#log4j.appender.Console=org.apache.log4j.ConsoleAppender  
#log4j.appender.Console.Target=System.out  
##可以靈活地指定日誌輸出格式,下面一行是指定具體的格式  
#log4j.appender.Console.layout = org.apache.log4j.PatternLayout  
#log4j.appender.Console.layout.ConversionPattern=[%c] - %m%n  
#  
##文件大小到達指定尺寸的時候產生一個新的文件  
#log4j.appender.File = org.apache.log4j.RollingFileAppender  
##指定輸出目錄  
#log4j.appender.File.File = logs/ssm.log  
##定義文件最大大小  
#log4j.appender.File.MaxFileSize = 10MB  
## 輸出所以日誌,如果換成DEBUG表示輸出DEBUG以上級別日誌  
#log4j.appender.File.Threshold = ALL  
#log4j.appender.File.layout = org.apache.log4j.PatternLayout  
#log4j.appender.File.layout.ConversionPattern =[%p] [%d{yyyy-MM-dd HH:mm:ss}][%c]%m%n

################################################################################
########數據庫記錄日誌的方式
log4j.logger.com.zjx.util=error,database
log4j.appender.database=org.apache.log4j.jdbc.JDBCAppender
log4j.appender.database.URL=jdbc:mysql://localhost:3306/test?characterEncoding=utf-8
log4j.appender.database.driver=org.gjt.mm.mysql.Driver
log4j.appender.database.user=root
log4j.appender.database.password=82651205
log4j.appender.database.sql=INSERT INTO t_log(content,logDate) VALUES ('%m','%d{yyyy-MM-dd}')
log4j.appender.database.layout=org.apache.log4j.PatternLayout
log4j.appender.database.layout.ConversionPattern=%m

mybatis.cfg.xml

<?xml version="1.0" encoding="UTF-8"?>  
<!DOCTYPE configuration  PUBLIC   "-//mybatis.org//DTD Config 3.0//EN"  "http://mybatis.org/dtd/mybatis-3-config.dtd">  
<configuration>    
    <typeAliases>
        <!-- 如果還有其餘的映射類,則繼續添加 -->
        <typeAlias type="com.zjx.bean.UserBean" alias="user"/>
    </typeAliases>


</configuration>  

UserBean.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="user">
    <!-- 結果集映射 -->
    <resultMap type="user" id="userMap">
        <result property="passWord" column="pwd"/>
    </resultMap>
    <select id="findById" parameterType="int" resultMap="userMap">
        select * from t_user where id = #{id};
    </select>

    <!-- 字段模糊的動態語句 -->
    <sql id="paramSql">
        <if test="userName !=null and userName != ''">
             and userName like '%${userName}%' 
        </if>
    </sql>

    <select id="findPage" resultMap="userMap">
        select * from t_user
        where 1=1 <include refid="paramSql"></include> 
        limit #{start},#{pageSize}
    </select>
    <select id="findCount" resultType="int">
        select count(*) from t_user where 1=1 <include refid="paramSql"></include>
    </select>


</mapper>

3.Junit測試

表自己建好,我也懶

那麼首先書寫實體:

package com.zjx.bean;

import java.sql.Date;


/** 
  * @Description 用戶實體類
  * @author tony_kanper
  * @date 2016年1月20日 上午11:30:32 
  * @version V1.0 
  * 
  */
public class UserBean {
    /**
     * id
     */
    private int id;
    /**
     * 用戶名
     */
    private String userName;
    /**
     * 生日
     */
    private Date birthday;
    /**
     * 密碼
     */
    private String passWord;
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getUserName() {
        return userName;
    }
    public void setUserName(String userName) {
        this.userName = userName;
    }
    public Date getBirthday() {
        return birthday;
    }
    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }
    public String getPassWord() {
        return passWord;
    }
    public void setPassWord(String passWord) {
        this.passWord = passWord;
    }
    @Override
    public String toString() {
        return "UserBean [id=" + id + ", userName=" + userName + ", birthday="
                + birthday + ", passWord=" + passWord + "]";
    }
    public UserBean(String userName, Date birthday, String passWord) {
        super();
        this.userName = userName;
        this.birthday = birthday;
        this.passWord = passWord;
    }
    public UserBean() {
        super();
    }

}

業務接口Service

package com.zjx.service;

import com.zjx.bean.CutPageBean;
import com.zjx.bean.UserBean;

/** 
  * @Description: 用戶業務接口
  * @author tony_kanper
  * @date 2016年1月20日 上午11:30:50 
  * @version V1.0 
  * 
  */
public interface IUserService {
    /**
     * 每頁顯示記錄數
     */
    public final int PAGESIZE = 10;
    /**
     * @Desciption 按照用戶id查找該用戶
     * @param id 用戶id
     * @return 用戶實體
     */
    public UserBean findById(int id);


    /**
     * @Description 按照頁碼和用戶姓名模糊字查找用戶分頁對象
     * @param pageNO 頁碼
     * @param userName 用戶姓名模糊字
     * @return 分頁對象
     */
    public CutPageBean<UserBean> findByItem(int pageNO,String userName);
}

業務接口實現類ServiceImpl超類和具體實現類

package com.zjx.service.impl;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.stereotype.Service;

import com.zjx.bean.CutPageBean;
/** 
  * @Description 所有業務實現類的超類
  * @author tony_kanper
  * @date 2016年1月20日 上午11:31:07 
  * @version V1.0 
  *
  * @param <T> 通用泛型
  */
@Service
public class BaseService<T> {
    /**
     * SqlSesion模板類
     */
    @Resource
    protected SqlSessionTemplate session;

    /**
     * @Description 所有的查詢分頁對象的超類方法
     * @param pageNO 頁碼
     * @param pageSize 每頁顯示記錄數
     * @param paramMap 需要查詢的字段集合
     * @param listSql 查詢某頁記錄的SQL語句
     * @param countSql 查詢總記錄數的SQL語句
     * @return 分頁對象
     */
    public CutPageBean<T> cutpage(int pageNO, int pageSize,
            Map<String, Object> paramMap, String listSql, String countSql) {
        CutPageBean<T> cutBean = new CutPageBean<T>();
        if (paramMap == null) {
            paramMap = new HashMap<String, Object>();
        }
        // 設置查詢的起始頁
        paramMap.put("start", (pageNO - 1) * pageSize);
        // 設置查詢頁開始向後的記錄數
        paramMap.put("pageSize", pageSize);

        // 查詢Mybatis配置文件下,命名空間內的查詢結果
        List<T> list = this.session.selectList(listSql, paramMap);
        cutBean.setList(list);

        // 設置總記錄數
        int count = this.session.selectOne(countSql, paramMap);
        cutBean.setCount(count);

        // 設置總頁數
        cutBean.setTotalPage(count / pageSize);
        if (count % pageSize != 0) {
            cutBean.setTotalPage(count / pageSize + 1);
        }
        return cutBean;
    }

}

具體實現類如下

package com.zjx.service.impl;

import java.util.HashMap;
import java.util.Map;

import org.springframework.stereotype.Service;

import com.zjx.bean.CutPageBean;
import com.zjx.bean.UserBean;
import com.zjx.service.IUserService;
/** 
  * @Description 用戶業務實現類 
  * @author tony_kanper
  * @date 2016年1月20日 上午11:50:57 
  * @version V1.0 
  * 
  */
@Service
public class UserServiceImpl extends BaseService<UserBean> implements IUserService {

    @Override
    public UserBean findById(int id) {
        // 測試切面類是否完成錯誤記錄進入數據庫時,解除註釋
        // throw new NullPointerException();
        return session.selectOne("user.findById", id);
    }

    @Override
    public CutPageBean<UserBean> findByItem(int pageNO, String userName) {
        Map<String, Object> paramMap = new HashMap<>();
        paramMap.put("userName", userName);
        return cutpage(pageNO, PAGESIZE, paramMap, "user.findPage", "user.findCount");
    }

}

測試類:

測試類超類:

package com.zjx.test;

import org.junit.After;
import org.junit.Before;
import org.springframework.beans.BeansException;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.util.StringUtils;


public class UnitTestBase {
    /**
     * 相對路徑應用上下文
     */
    private ClassPathXmlApplicationContext context;

    /**
     * XML文件的存放路徑
     */
    private String springXmlPath;

    public UnitTestBase() {

    }

    public UnitTestBase(String springXmlPath){
        this.springXmlPath = springXmlPath;
    }
    /**
     * 加載XML文件
     */
    @Before
    public void before(){
        if (StringUtils.isEmpty(springXmlPath)) {
            springXmlPath = "classpath*:spring-*.xml";
        }
        try {
            // 多個xml文件用逗號或者空格符隔開,均可加載
            context = new ClassPathXmlApplicationContext(springXmlPath.split("[,\\s]+"));
            context.start();
        } catch (BeansException e) {
            e.printStackTrace();
        }
    }
    /**
     * 銷燬
     */
    @After
    public void after(){
        context.destroy();
    }

    /**
     * @param beanId SpringXML文件中的bean的id
     * @return 該bean的id對應下的實例,默認單例
     */
    @SuppressWarnings("unchecked")
    protected <T extends Object> T getBean(String beanId){
        try {
            return(T)context.getBean(beanId);
        } catch (BeansException e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * @param clazz 通過類模板獲取該類
     * @return 該類的實例,默認單例
     */
    protected <T extends Object> T getBean(Class<T> clazz){
        try {
            return context.getBean(clazz);
        } catch (BeansException e) {
            e.printStackTrace();
            return null;
        }
    }
}

測試類

package com.zjx.test;

import org.junit.runner.RunWith;
import org.junit.runners.BlockJUnit4ClassRunner;

import com.zjx.service.IUserService;

@RunWith(BlockJUnit4ClassRunner.class)
public class Test extends UnitTestBase{
    public Test() {
        super("classpath:applicationContext-base.xml");
    }
    @org.junit.Test
    public void testUnit(){ 
        IUserService service = super.getBean("userServiceImpl");
        System.out.println(service.findByItem(1, "張"));
    }

}

這樣測試,免去了註釋實現類中的測試類的麻煩,並且在pom.xml中設置了scope它僅在測試時引入這個包,實際使用時,並不會用到

<!-- 單元測試的依賴 --> 
<dependency>
  <groupId>junit</groupId>
  <artifactId>junit</artifactId>
  <version>4.10</version>
  <scope>test</scope>
</dependency>   

4.Spring整合JSON輸出

也許小夥伴會問,不是說好了,要來玩JSON嗎?

<!--避免IE執行AJAX時,返回JSON出現下載文件 -->  
<bean id="mappingJacksonHttpMessageConverter"  
    class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">  
    <property name="supportedMediaTypes">  
        <list>  
            <!-- 設置返回的編碼和解析方式 -->
            <value>text/html;charset=UTF-8</value>  
        </list>  
    </property>  
</bean>  
<!-- 啓動SpringMVC的註解功能,完成請求和註解POJO的映射 -->  
<bean  
    class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">  
    <property name="messageConverters">  
        <list>  
            <ref bean="mappingJacksonHttpMessageConverter" /> <!-- JSON轉換器 -->  
        </list>  
    </property>  
</bean>  

Spring對JSON的支持也挺噁心的,如果Spring的版本足夠高,他對JSON的支持會用到配置文件中的MappingJackson2HttpMessageConverter,注意這個Jackson2,如果你按着ctrl沒鏈接,那麼把2刪除,說明你用的Spring版本是之前的,你用的json版本1也都足夠了,如果你只能用2,那麼,你的pom.xml中必須加入2.0版本以上的依賴,對此Spring上的說明也是這樣的,樓主看了很久的源碼= =,快給我點贊

<!-- 映入JSON2.5支持 --> 

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-annotations</artifactId>
    <version>2.5.1</version>
</dependency>
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.5.1</version>
</dependency> 
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-core</artifactId>
    <version>2.5.1</version>
</dependency>

由圖可知,在類的註釋上最後一行,說明MappingJackson2HttpMessageConverter兼容Jackson 2.1和更高版本,之所以貼出來說,是想說明看源碼很重要,也想說明我不是亂說的

接下來寫一個JSP頁面發送AJAX請求試試

<%@ page language="java" pageEncoding="UTF-8"%>
<html>
<body>
<h2>Hello World!</h2>
<hr/>
<a href="/zjx/user/nextPage.do">去看看用戶頁</a>
<script type="text/javascript" src="/zjx/jquery-2.1.4.min.js"></script>
<script type="text/javascript">
    $(function(){
        $.post("/zjx/user/findById.do","id=1",function(data){
                alert(data);
                });
    });

</script>
</body>
</html>

action控制層:

package com.zjx.action;

import javax.annotation.Resource;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import com.zjx.bean.CutPageBean;
import com.zjx.bean.UserBean;
import com.zjx.service.IUserService;

/** 
  * @Description 用戶控制器
  * @author tony_kanper
  * @date 2016年1月20日 上午11:33:46 
  * @version V1.0 
  * 
  */
@Controller
@RequestMapping("/user")
public class UserAction {
    /**
     * 注入的業務接口
     */
    @Resource
    private IUserService service;

    /**
     * @Description 根據視圖層傳入的id調用業務方法查找到用戶後採用轉換爲JSON對象返回
     * @param id 用戶id
     * @return 用戶實體的JSON對象
     */
    @RequestMapping("/findById")
    @ResponseBody//Spring集成的JSON,可以將Model轉換爲JSON對象存放在HttpServletResponse中
    private UserBean findById(int id){
        return service.findById(id);    
    }
    /**
     * @Description 按照頁碼和姓名模糊字查找某頁全部用戶對象
     * @param pageNO 頁碼
     * @param userName 用戶姓名模糊字
     * @return 某頁全部用戶對象(JSON)
     */
    @RequestMapping("/findByPageAndName")
    @ResponseBody
    private CutPageBean<UserBean> findByPageAndName(int pageNO,String userName){
        return service.findByItem(pageNO, userName);
    } 
    /**
     * @Description 測試是否跳轉去WEB-INF目錄下的jsp頁面
     * @return 返回視圖的名稱
     */
    @RequestMapping("/nextPage")
    private String nextPage(){
        return "allUserPage";
    }
}

嘿,通過測試,還真的在頁面拿到了JSON數據呢,好神奇啊

5.Spring整合Mybatis不需要寫DAO層代碼

話說,倪們看到我寫了DAO層代碼了嗎?因爲DAO已經寫到UserBean.xml中和配置裏了,要是不懂這個XML裏面怎麼寫SQL語句,就網上或者買書看看,不多說;

這裏值得一提的是,我用了SqlSessionTemplate這個類,這個類有點搞笑,他是自動管理的,也就是說,他的創建銷燬是不必依賴Spring的,也就是說,當SQL模版類查詢結束之後,他自己就知道關閉了,而懂點SpringIOC的筒子都知道,bean默認是單例的,那麼要是他自己關了,或者別人又用了這個類,併發的訪問扎個辦?答案是:你知道Mybatis的工程師有多騷不?

這個SqlSessionTemplate的註釋是這個意思,他是線程安全的,是受Spring管理的,和Spring事務管理器一起工作保證只用在一個當前的線程,它也是Spring管理下的事務內;此外,它管理會話的生命週期,包括關閉,提交或回滾基於Spring事務配置必要的

看到這裏,也就是說,Mybatis的工程師們,把這個棘手的問題甩給Spring去管,他們就當甩手掌櫃了啊,反正有mybatis-spring.jar這個提供對Spring支持的神器在

<!-- mybatis對spring的支持 -->  
<dependency>  
    <groupId>org.mybatis</groupId>  
    <artifactId>mybatis-spring</artifactId>  
    <version>1.2.3</version>  
</dependency> 

也正是如此,我們在配置base的時候,會將模版類設置爲多例,我問騷年你爲何如此勇敢,因爲它是線程安全的,也受Spring的管理

<!-- 配置SqlSession模版類,SqlSessionTemplate是線程安全類 -->
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate" scope="prototype">
    <constructor-arg  ref="sessionFactory"></constructor-arg>       
</bean>

另外,就算你不寫這個多例,也不影響,最多報個警告

WARN DisposableBeanAdapter:364 - Invocation of destroy method ‘close’ failed on bean with name ‘sqlSession’: java.lang.UnsupportedOperationException: Manual close is not allowed over a Spring managed SqlSession

這個警告是說,在Spring管理下的sqlSession是不允許自己關閉的

PS:如果有大神找到其中更深的緣由,請不吝賜教

6. Log4j控制輸出

關於Log4j的東西,網上太多了,各位慢慢看,個人覺得這篇博文蠻不錯

Log4j配置詳解

關於擴展輸出的,我用的是AOP方式

工具類如下:

package com.zjx.util;

import java.sql.Date;
import java.text.SimpleDateFormat;

import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Service;


/** 
  * @Description 日誌處理類
  * @author tony_kanper
  * @date 2016年1月20日 上午11:39:48 
  * @version V1.0 
  * 
  */
@Service
@Aspect
public class LogRecord {

    /**
     * 日期格式化輸出對象
     */
    private SimpleDateFormat df = new SimpleDateFormat("HH:mm:ss");
    /**
     * 日誌對象
     */
    private Logger log = Logger.getLogger(LogRecord.class);

    /**
     * @Description 在方法拋出異常之後,記錄異常信息,並將異常信息以error等級封裝到log對象中
     * @param point 切入點
     * @param e 方法拋出的異常
     */
    @AfterThrowing(value = "execution(* com.zjx.service.impl.*.*(..))", throwing = "e")
    public void writeLog(JoinPoint point, Exception e) {
        // 得到目標對象的類名
        String className = point.getTarget().getClass().getName();
        // 得到目標對象的方法名
        String methodName = point.getSignature().getName();

        // 當前日期
        String timeStr = df.format(new Date(System.currentTimeMillis()));
        // 得到異常類信息
        String exceptionStr = e.getClass().getName();

        String info = timeStr+" 在"+className+"的 "+methodName+"()方法,拋出"+exceptionStr+"異常";
        //System.out.println(info);
        log.error(info);
    }
}

一旦在com.zjx.service.impl包下的所有類的所有方法拋出異常之後,都會向log日誌對象寫入錯誤信息,並且在log4j配置文檔中寫入數據庫,經測試無誤

PS:對於環繞通知,和其它通知方式,關於訂單類的記錄,有大神會的,希望給我一個DEMO謝謝

附上郵箱:[email protected]

7.代碼註釋的規範

之前的項目也不是無可挽救,但是代碼實在是太糟糕了,沒用註釋,或者關鍵性的註釋用單行註釋而不用文檔註釋,這對於代碼閱讀是相當困難的

對於文檔註釋,可以生成Javadoc,同時,當鼠標浮動到具有文檔註釋的類/方法/變量時,能提供說明,簡單粗暴

通常我們可以在Myeclipse中配置你的註釋樣本

如圖,我的文件註釋上,擁有標題,包,文件描述,作者創建日期等信息

當然,你也可以通過Edit編輯你的輸出樣式

然後你可以按住Alt+Shirft+J快速在相應位置生成註釋

最後你只需要填就是了

程序員一定要養成寫註釋的習慣,不關多大的公司,就說國內的支付寶,別個寫對外接口不也一樣寫好的文檔註釋和代碼的單行註釋,我等菜鳥,更應該如此,這更多的是爲了今後的程序員便於維護,而不是爲了你看懂(當然你肯定希望別人寫好註釋)

8.最後

花了很多時間學習這些,最後的收穫也蠻大,希望能遇到更多志同道合的朋友

項目中容易遇到的問題主要有這些,有的問題之前我已經提到了

  1. MAVEN環境變量的配置,在path中加入%MAVEN_HOME%\bin;如果還需要配置jar包的倉庫可以參看博文MyEclipse+Tomcat+MAVEN+SVN項目完整環境搭建
  2. 對於SqlSession報錯的問題,要加多例
  3. 對於Spring配置文件讀取jdbc.properties文件時,報錯,有可能是mySQL的權限驗證問題,它會默認使用系統的userName,解決方案有兩種,一種參看博文mysql啓動問題access denied for user ‘root’@’localhost’(using password:YES) 另一種是找到mysql安裝目錄,在my.ini中,以記事本打開的文末添加–skip-grant-tables
  4. 對於Spring版本較低的,Json,可以用如下依賴



    org.codehaus.jackson
    jackson-mapper-asl
    1.9.13

  5. MAVEN倉庫傳送門MAVEN倉庫,你只需要像百度一樣在搜索欄中輸入jar,它們自動會爲你找到最新版本jar包依賴

  6. Myeclipse GA 2014的下載門,做爲程序員肯定要用最新版的哇,遇到問題去解決就是了,不要怕遇到問題而用舊版,很多過時方法和不支持的東西,新的東西,永遠更多插件支持,永遠兼容舊版http://www.my-eclipse.cn/
  7. 如果有興趣,可以關注我的CSDN http://blog.csdn.net/kang82651204/

本文源碼:
http://download.csdn.net/detail/kang82651204/9412243

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章