大學四年,即將畢業!
大學期間的最后一篇博客,總結分享下我做的畢業設計。我選的論文命題為《燃氣管網設備儀器進銷存管理系統之后台設計》,由於我們專業只有我一個走技術路線,所以,我一個人完成了整個系統的設計及開發,總耗時近一個月,最終獲得優的成績。
這里不討論論文,不寫具體實現細節,主要講如何一步步搭建自己的系統框架及系統實現,分享下自己的心得,新手可以互相學習,大牛們就當看作本人拋磚引玉啦!!
博客最后會附上系統開發相關的所有文件但不包括畢業論文,本文已大體包含了論文的內容!
一、系統展示
1.登錄頁面
2.admin登錄后的主頁
3.菜單管理
4.角色管理>新增角色
5.用戶管理
6.添加商品
7.倉庫管理
8.供應商管理
9.采購訂單管理
10.采購訂單導出
11.庫存查看
12.采購統計
二、系統需求分析
上面簡單的展示了完成后的系統測試截圖,你可以下載war包部署到自己的tomcat上看,下面開始進入正文。
開發一個(簡單)系統,我想首要做的就是進行系統需求分析,弄清楚你為什么要做這個系統,這個系統有哪些功能模塊,每個功能具體實現些什么功能。
當然,我這里的主要目的是完成畢業設計,交出畢業論文。但我並沒有簡單的只是為了完成一個畢業設計而去開發這個系統。主要想法是以開發這套進銷存管理系統為例,詳細說明一個系統從確認需求、技術選型、架構設計、系統實現到測試部署的整個開發過程。綜合運用自己平時所學的知識、技術,及實習獲得的經驗等,去完整且較好的實現一個系統。搭建一個基礎系統框架,形成一定規范,以后在此基礎上做開發,可以省去很多諸如搭建框架、加入依賴、配置等工作。
這次開發所做的主要工作及意義如下:
①學會站在用戶的角度分析用戶需求,完成需求分析設計等。
②熟練使用各種類相關開發、設計工具,及開源軟件。
③熟練掌握Spring+SpringMVC+Hibernate+ExtJs的開發技術。
④熟練使用maven構建工具。
⑤站在企業的角度,試着搭建自己的一個底層基礎框架。
⑥建立完整的燃氣管進銷存管理系統,進行測試並分析結果。
⑦將系統部署到互聯網上,以實現真正的web應用。
1.問題分析
首先,對系統進行需求分析,首先需要了解的就是什么是進銷存系統,進銷存系統也稱為供應鏈管理系統,最基本的內容就是采購、庫存、銷售、退貨管理。進銷存系統是對企業生產經營中采購、入庫、銷售進行跟蹤管理,從采購單開始,到商品入庫,商品銷售出庫,每一步都跟蹤記錄。有效解決企業的分銷管理等業務問題。那么燃氣管進銷存系統有何不同呢,其實進銷存系統已經具備了一般商品的進銷存功能,燃氣管就是一種商品。以此為出發點,開始着手設計系統功能模塊。
2.系統模塊結構
系統分為6大模塊,分別是基礎設置、采購管理、銷售管理、庫存管理、統計分析、系統管理。系統設置的角色有admin、采購員、銷售員、庫存管理員等。
系統模塊結構(使用xmind設計):
3.系統總體流程
系統的一個整體流程,從初次使用開始,系統設置一個超級管理員(admin),擁有系統的所有權限。admin登錄系統,設置角色(系統管理員,采購員,銷售員,庫存管理員),分配對應的權限。然后進入用戶管理,錄入系統用戶。一般管理員登錄系統,錄入基礎數據;采購員需要錄入供應商,采購單,退貨單;銷售員則需錄入銷售單,退貨單。庫存管理員就需要在庫存管理中進行采購審核和銷售審核,采購審核通過則商品入庫,增加庫存;銷售審核通過則商品出庫,減少庫存。管理員還可以查看每月的采購統計和銷售統計。
系統總體流程(使用visio設計):
三、開發環境簡介
需求確定了,就要進入具體的開發階段,首先確定開發這個系統綜合用到哪些技術、開發工具等。
簡單說下這個系統的開發環境:
開發平台:windows 8.1
Java版本:jdk 1.8
項目管理工具:Maven
開發工具:Intellij IDEA
數據庫:MySql 5.1
服務器:Tomcat 8.5
開發框架:Spring4 + SpringMVC + Hibernate5
前端框架:ExtJs 4.2 + Jsp
建模工具:PowerDesigner、Visio
1.maven
Maven是Apache軟件基金會組織維護的一款自動化構建工具,專注服務於Java平台的項目構建和依賴管理。它提供了中央倉庫,能幫我們自動下載構件和第三方的開源類庫。你只需要在你的項目中以坐標的方式依賴一個jar包,maven就會自動從中央倉庫下載,並同時下載這個jar包所依賴的其他jar包,以及可以下載源碼進行閱讀。使用maven后每個jar包本身只在本地倉庫中保存一份,極大的節約了存儲空間,讓項目更輕巧,更避免了重復文件太多而造成的混亂。同時maven可以替我們自動的將當前jar包所依賴的其他所有jar包全部導入進來,無需人工參與,節約了大量的時間和精力。使用maven,只需要一條簡單的命令,就可以自動完成清理、編譯、測試、打包、部署的整個過程。我們的項目一般會分為開發環境和生產環境,不同環境對應不同的配置文件,使用maven,你就可以配置兩個環境,打包的時候指定運行的環境,就可以將對應的配置文件替換,以此減少手工操作及可能帶來的失誤操作等。
2.Intellij IDEA
IDEA是java語言開發的集成環境,Intellij被公認為最好的Java開發工具之一。IDEA在代碼自動提示、重構、調試、各類版本工具(maven、svn等)整合等方面都是比較強的。本人是在實習期間轉用idea開發的,之前一直使用eclipse,相比eclipse,idea在調試、代碼自動提示等方面更顯優勢。項目在idea中有一個更友好的目錄結構,尤其是多工程項目。當然,eclipse比idea更容易上手,使用idea可以提高你的開發速度,但前提是你需要記住大量的快捷鍵。使用idea的調試功能,比如,你只需要按快捷鍵Alt+F8,然后輸入表達式,就可以快速求值;在調試的時候,idea會在變量的后面以不同的顏色顯示變量的值,你就可以很清楚的知道調試的每一步,非常方便。使用好IDEA能在很大程度上提高我們的開發速度。
3.ExtJs
ExtJs可以用來開發富客戶端的ajax應用,是用javascript寫的與后台技術無關的前端ajax框架,主要用於創建前端用戶界面,擁有強大的數據處理功能,以及圖表統計等。同時,ExtJs擁有很多個性化的主題供你選擇,是開發后台管理系統的一個不錯的選擇。
四、底層架構設計
在進行進銷存系統的設計和編碼之前,首先設計一個自己的底層框架,這個底層框架在之后可以作為其它具體項目開發的一個基礎,從而不必每次開發項目時,都去做很多重復的工作。這個底層框架主要包括一個開發的規范,以及一些通用的工具類等,更重要的是分類別引入各個框架,如Spring、Hibernate、各個配置文件等。同時,如果以后在開發中,增加的一些新功能,還可以往這個底層中添加,不斷的去完善。
1.規范
在進行框架設計之前,為了使軟件開發過程順暢、提高代碼的可靠性,可讀性和可維護性等,首先需要確定的就是開發規范了,俗話說,沒有規矩不成方圓,軟件開發亦是如此。下面列出一些簡單的需要遵守的規范。
1.1基礎規范
首先需要遵守的是一些基礎規范。一般來說,公司會將域名作為所有命名的一個基礎,比如文件名、包名等等。因此我申請了一個域名[www.lyyzoo.com]作為個人域名。然后將D:/lyyzoo-repo作為開發的根目錄,即個人代碼倉庫,以后所有的項目都會建到這個目錄下。所有的項目開發使用maven來管理項目,因此目錄結構是標准的maven規范目錄。
maven約定的目錄結構:
1.2代碼規范
①命名
> 所有的命名需要見名之意,盡量保證通過變量名得知變量的含義,需要注釋的地方盡量添加注釋。
> 包命名全小寫,通過域名倒寫+模塊的形式,如:com.lyyzoo.service
> 類命名采用Pascal名法,大寫字母開頭,每個單詞首字母大寫。
> 方法名采用Camel命名法,小寫字母開頭,每個單詞首字母小寫;getter和setter使用Lombok自動生成,只需添加@Data注解即可。
> 變量名采用Camel命名法,小寫字母開頭,每個單詞首字母大寫。變量名不宜過長,可采用首字母縮寫的形式,但要見名之意。
> 常量名全大寫,每個單詞之間使用”_”分隔。
②分層
項目以功能模塊划分,不同項目建立不同的工程,使用maven的依賴進行管理。包的基本分層有controller(控制層)、service(業務層)、dao(數據訪問層)、entity(模型層)。
2.架構設計
2.1模塊結構
整個項目的底層着重是一些通用的、基礎的東西,整合到一起,以便於以后重用。首先,創建一個名為lyyzoo的maven工程,lyyzoo將作為底層的根目錄。lyyzoo下有兩個主要的子模塊,分別為lyyzoo-base和lyyzoo-starter,lyyzoo-base是基礎模塊,用於一些簡單的Java及JavaEE程序;lyyzoo-starter則是JavaEE相關,會依賴於lyyzoo-base,同時引入了Spring、Hibernate等第三方框架。然后在各個模塊中添加具體的子模塊。以后開發中需要用到哪個模塊,在依賴中添加那個模塊即可。
底層模塊結構圖:
以下是各個POM之間的關系:
① lyyzoo > pom.xml
② lyyzoo-base > pom.xml
③ lyyzoo-starter > pom.xml
2.2依賴管理
結構建好后,就需要進行一些詳細的依賴配置工作了,lyyzoo是所有模塊的父類,所以在lyyzoo中需要添加公用的屬性、依賴管理、maven插件等。
首先將所有的版本號提出來,放到<properties></properties>里,這樣一旦需要切換到另一個版本時,就可以只改個版本號就達到目的了。其中列出了一些屬性如下:包括底層的版本、Java版本、Spring、Hibernate的版本等等。

1 <properties> 2 <!-- Global --> 3 <lyyzoo.version>1.0-SNAPSHOT</lyyzoo.version> 4 <java.version>1.8</java.version> 5 <maven.compiler.source>${java.version}</maven.compiler.source> 6 <maven.compiler.target>${java.version}</maven.compiler.target> 7 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> 8 <!-- lombok --> 9 <lombok.version>1.16.14</lombok.version> 10 <!-- log --> 11 <slf4j.version>1.7.7</slf4j.version> 12 <logback.version>1.1.3</logback.version> 13 <!-- jdbc --> 14 <mysql.version>5.1.38</mysql.version> 15 <!-- http://mvnrepository.com/artifact/com.mchange/c3p0/ --> 16 <c3p0.version>0.9.5.2</c3p0.version> 17 <!-- test --> 18 <junit.version>4.12</junit.version> 19 <!-- servlet --> 20 <servlet.version>3.1.0</servlet.version> 21 <!-- spring --> 22 <spring.version>4.2.6.RELEASE</spring.version> 23 <aspectjrt.version>1.7.3</aspectjrt.version> 24 <aspectjweaver.version>1.7.3</aspectjweaver.version> 25 <!-- hibernate --> 26 <hibernate.version>5.0.1.Final</hibernate.version> 27 <hibernate.jpa.version>1.0.0.Final</hibernate.jpa.version> 28 </properties>
接着,引入依賴管理,在lyyzoo中引入其它項目將會用到的所有三方jar包的依賴,所有的依賴都添加到<dependencyManagement><dependencies></dependencies></dependencyManagement>中,這樣就可以方便的管理所有的jar包了。下面列出引入的一部分jar包,其它的可參考源碼。
① 首先需要引入lyyzoo下的其它模塊,如lyyzoo-base-core、lyyzoo-starter-base等模塊。

1 <!-- lyyzoo --> 2 <dependency> 3 <groupId>com.lyyzoo</groupId> 4 <artifactId>lyyzoo-base-core</artifactId> 5 <version>${lyyzoo.version}</version> 6 </dependency> 7 <dependency> 8 <groupId>com.lyyzoo</groupId> 9 <artifactId>lyyzoo-base-data</artifactId> 10 <version>${lyyzoo.version}</version> 11 </dependency> 12 <dependency> 13 <groupId>com.lyyzoo</groupId> 14 <artifactId>lyyzoo-starter-base</artifactId> 15 <version>${lyyzoo.version}</version> 16 </dependency> 17 <dependency> 18 <groupId>com.lyyzoo</groupId> 19 <artifactId>lyyzoo-starter-jpa</artifactId> 20 <version>${lyyzoo.version}</version> 21 </dependency>
② JDBC相關,相關jar包有c3p0,用於作數據庫連接池;mysql驅動包;dbutils,對JDBC進行了簡單的封裝,使用起來簡單方便。

1 <!-- jdbc --> 2 <dependency> 3 <groupId>com.mchange</groupId> 4 <artifactId>c3p0</artifactId> 5 <version>${c3p0.version}</version> 6 </dependency> 7 <dependency> 8 <groupId>mysql</groupId> 9 <artifactId>mysql-connector-java</artifactId> 10 <version>${mysql.version}</version> 11 </dependency> 12 <dependency> 13 <groupId>commons-dbutils</groupId> 14 <artifactId>commons-dbutils</artifactId> 15 <version>1.5</version> 16 </dependency>
③ 日志相關:

1 <!-- log --> 2 <dependency> 3 <groupId>org.slf4j</groupId> 4 <artifactId>slf4j-api</artifactId> 5 <version>${slf4j.version}</version> 6 </dependency> 7 <dependency> 8 <groupId>ch.qos.logback</groupId> 9 <artifactId>logback-classic</artifactId> 10 <version>${logback.version}</version> 11 </dependency> 12 <!-- slf4j --> 13 <dependency> 14 <groupId>org.slf4j</groupId> 15 <artifactId>log4j-over-slf4j</artifactId> 16 <version>${slf4j.version}</version> 17 </dependency>
④ spring相關,包括了spring aop、spring mvc等。

1 <!-- springframework --> 2 <dependency> 3 <groupId>org.springframework</groupId> 4 <artifactId>spring-aop</artifactId> 5 <version>${spring.version}</version> 6 </dependency> 7 <dependency> 8 <groupId>org.springframework</groupId> 9 <artifactId>spring-aspects</artifactId> 10 <version>${spring.version}</version> 11 </dependency> 12 <dependency> 13 <groupId>org.springframework</groupId> 14 <artifactId>spring-beans</artifactId> 15 <version>${spring.version}</version> 16 </dependency> 17 <dependency> 18 <groupId>org.springframework</groupId> 19 <artifactId>spring-context</artifactId> 20 <version>${spring.version}</version> 21 </dependency> 22 <dependency> 23 <groupId>org.springframework</groupId> 24 <artifactId>spring-context-support</artifactId> 25 <version>${spring.version}</version> 26 </dependency> 27 <dependency> 28 <groupId>org.springframework</groupId> 29 <artifactId>spring-core</artifactId> 30 <version>${spring.version}</version> 31 </dependency> 32 <dependency> 33 <groupId>org.springframework</groupId> 34 <artifactId>spring-jdbc</artifactId> 35 <version>${spring.version}</version> 36 </dependency> 37 <dependency> 38 <groupId>org.springframework</groupId> 39 <artifactId>spring-jms</artifactId> 40 <version>${spring.version}</version> 41 </dependency> 42 <dependency> 43 <groupId>org.springframework</groupId> 44 <artifactId>spring-orm</artifactId> 45 <version>${spring.version}</version> 46 </dependency> 47 <dependency> 48 <groupId>org.springframework</groupId> 49 <artifactId>spring-tx</artifactId> 50 <version>${spring.version}</version> 51 </dependency> 52 <dependency> 53 <groupId>org.springframework</groupId> 54 <artifactId>spring-web</artifactId> 55 <version>${spring.version}</version> 56 </dependency> 57 <dependency> 58 <groupId>org.springframework</groupId> 59 <artifactId>spring-webmvc</artifactId> 60 <version>${spring.version}</version> 61 </dependency>
⑤ hibernate相關:

1 <dependency> 2 <groupId>org.hibernate</groupId> 3 <artifactId>hibernate-c3p0</artifactId> 4 <version>${hibernate.version}</version> 5 </dependency> 6 <dependency> 7 <groupId>org.hibernate.common</groupId> 8 <artifactId>hibernate-commons-annotations</artifactId> 9 <version>${hibernate.version}</version> 10 </dependency> 11 <dependency> 12 <groupId>org.hibernate</groupId> 13 <artifactId>hibernate-core</artifactId> 14 <version>${hibernate.version}</version> 15 </dependency> 16 <dependency> 17 <groupId>org.hibernate</groupId> 18 <artifactId>hibernate-entitymanager</artifactId> 19 <version>${hibernate.version}</version> 20 </dependency>
所有的依賴添加好后,就需要為各個子模塊添加具體的依賴了,根據每個子模塊的功能,添加相關的依賴,而不是將所有的依賴一次性加入。這樣我們就可以根據自己開發的項目的需要,添加模塊依賴,而不是一次性加入所有jar包,避免冗余,增大項目的體積。下面以lyyzoo-base-data和lyyzoo-starter-jpa為例說明。
lyyzoo-base-data模塊是基礎數據相關,主要與數據庫打交道,那么就需要引入mysql驅動、數據庫連接池c3p0等,pom.xml如下:

1 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 2 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 3 <modelVersion>4.0.0</modelVersion> 4 <parent> 5 <groupId>com.lyyzoo</groupId> 6 <artifactId>lyyzoo-base</artifactId> 7 <version>1.0-SNAPSHOT</version> 8 </parent> 9 <artifactId>lyyzoo-base-data</artifactId> 10 <name>${project.artifactId}</name> 11 <packaging>jar</packaging> 12 13 <dependencies> 14 <!-- dbutils --> 15 <dependency> 16 <groupId>commons-dbutils</groupId> 17 <artifactId>commons-dbutils</artifactId> 18 </dependency> 19 <!-- jdbc --> 20 <dependency> 21 <groupId>mysql</groupId> 22 <artifactId>mysql-connector-java</artifactId> 23 </dependency> 24 <dependency> 25 <groupId>com.mchange</groupId> 26 <artifactId>c3p0</artifactId> 27 </dependency> 28 <!-- test --> 29 <dependency> 30 <groupId>com.lyyzoo</groupId> 31 <artifactId>lyyzoo-base-test</artifactId> 32 <scope>test</scope> 33 </dependency> 34 </dependencies> 35 </project>
lyyzoo-starter-jpa是Java持久化相關,所以主要引入hibernate相關的依賴,同時,starter-jpa會依賴base-data及starter-base,pom.xml如下:

1 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 2 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 3 <modelVersion>4.0.0</modelVersion> 4 <parent> 5 <groupId>com.lyyzoo</groupId> 6 <artifactId>lyyzoo-starter</artifactId> 7 <version>1.0-SNAPSHOT</version> 8 </parent> 9 <artifactId>lyyzoo-starter-jpa</artifactId> 10 <name>${project.artifactId}</name> 11 <packaging>jar</packaging> 12 13 <dependencies> 14 <dependency> 15 <groupId>com.lyyzoo</groupId> 16 <artifactId>lyyzoo-base-data</artifactId> 17 </dependency> 18 <dependency> 19 <groupId>com.lyyzoo</groupId> 20 <artifactId>lyyzoo-starter-base</artifactId> 21 </dependency> 22 <dependency> 23 <groupId>org.hibernate</groupId> 24 <artifactId>hibernate-c3p0</artifactId> 25 </dependency> 26 <dependency> 27 <groupId>org.hibernate.common</groupId> 28 <artifactId>hibernate-commons-annotations</artifactId> 29 </dependency> 30 <dependency> 31 <groupId>org.hibernate</groupId> 32 <artifactId>hibernate-core</artifactId> 33 </dependency> 34 <dependency> 35 <groupId>org.hibernate</groupId> 36 <artifactId>hibernate-ehcache</artifactId> 37 </dependency> 38 <dependency> 39 <groupId>org.hibernate.javax.persistence</groupId> 40 <artifactId>hibernate-jpa-2.1-api</artifactId> 41 </dependency> 42 <dependency> 43 <groupId>org.hibernate</groupId> 44 <artifactId>hibernate-validator</artifactId> 45 </dependency> 46 <dependency> 47 <groupId>com.lyyzoo</groupId> 48 <artifactId>lyyzoo-starter-test</artifactId> 49 <scope>test</scope> 50 </dependency> 51 </dependencies> 52 </project>
2.3類結構
有了前面的基礎之后,接下來進行重點的類結構設計。底層需要做的最重要的工作就是將一些通用的類抽象出來,以便於以后重用,從而提高開發效率。例如返回結果和分頁類的封裝、通用的工具類、JDBC相關的操作等。
說明一下,整個底層很大一部分是從之前實習的公司(這個就不說了)直接拿過來的,有些則更改了。相信我拿取的這部分代碼並不會涉及機密問題,不用於商業用途,僅僅只是學習,應該沒多大問題。
(1) lyyzoo-base-core
lyyzoo-base-core 目錄結構:
lyyzoo-base-core是基礎核心,封裝了返回結果和加入了一些常用的工具類。
com.lyyzoo.bean包下封裝了BaseBean和Result,BaseBean是Bean類的一個基礎類,實現了序列化,重寫了toString()方法,如下:

1 package com.lyyzoo.bean; 2 3 import org.apache.commons.lang3.builder.ToStringBuilder; 4 import org.apache.commons.lang3.builder.ToStringStyle; 5 6 import java.io.Serializable; 7 8 /** 9 * BaseBean 實現序列化 <p> 10 * 11 * @author bojiangzhou 12 * @date 2017-03-27 13 */ 14 public abstract class BaseBean implements Serializable { 15 16 /** 17 * ToStringBuilder – 用於輔助實現Object.toString()方法<p> 18 */ 19 public String toString() { 20 return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE); 21 } 22 23 }
Result則封裝了返回的結果,這里主要與ExtJs相對應,ExtJs進行ajax請求時,返回success=true,會進入success()方法;返回success=false,會進入failure()方法。同時,封裝了返回消息、標識、錯誤信息等,便於前端拿到相應數據。

1 package com.lyyzoo.bean; 2 3 import lombok.Data; 4 5 import java.util.Map; 6 7 /** 8 * 封裝返回結果<p> 9 * 10 * @author bojiangzhou 11 * @date 2017-03-27 12 */ 13 @Data 14 public class Result extends BaseBean { 15 private static final long serialVersionUID = 1L; 16 17 /** 18 * 成功標志 19 */ 20 public boolean success; 21 /** 22 * 返回標示 23 */ 24 public Integer code; 25 /** 26 * 相關消息 27 */ 28 public String msg; 29 /** 30 * 相關數據 31 */ 32 public Object data; 33 /** 34 * 錯誤詳細 35 */ 36 public Map<String, Object> errors; 37 38 public Result() { 39 40 } 41 42 public Result(boolean success) { 43 this.success = success; 44 } 45 46 public Result(boolean success, Integer code, Object data, String msg) { 47 this(success); 48 this.code = code; 49 this.data = data; 50 this.msg = msg; 51 } 52 53 public Result(Integer code, Map<String, Object> errors, String msg) { 54 this.success = false; 55 this.code = code; 56 this.errors = errors; 57 this.msg = msg; 58 } 59 60 public boolean isSuccess() { 61 return this.success; 62 } 63 64 public boolean hasErrors() { 65 if (this.errors != null && this.errors.size() > 0) { 66 return true; 67 } 68 return false; 69 } 70 }
其它的主要是一些工具類,例如Arrays繼承了org.apache.commons.lang3.ArrayUtils,使得Arrays具有了豐富的操作集合的工具。再如Dates,Dates里封裝了大量的對日期操作的方法,比如格式化日期、獲取某個日期當天的開始時間和結束時間等。
(2) lyyzoo-starter-base
lyyzoo-starter-base 目錄結構:
lyyzoo-starter-base是web應用程序的一個基礎,主要封裝了基礎實體類以及spring-base和日志的配置。實體的頂層是AbstractEntity<ID extends Serializable>,AbstractEntity繼承BaseBean。AbstractEntity重寫了equals和hashCode方法,主要做的處理是,如果兩個實體的id相同也算這兩個對象為同一個對象。代碼如下:

1 package com.lyyzoo.data.entity; 2 3 import com.lyyzoo.bean.BaseBean; 4 5 import java.io.Serializable; 6 7 /** 8 * 抽象實體類 重寫equals和hashCode方法 9 * 10 * @author bojiangzhou 11 * @date 2017-03-28 12 */ 13 @SuppressWarnings("serial") 14 public abstract class AbstractEntity<ID extends Serializable> extends BaseBean implements Serializable { 15 16 public abstract ID getId(); 17 18 @Override 19 public boolean equals(Object obj) { 20 21 if (null == obj) { 22 return false; 23 } 24 if (this == obj) { 25 return true; 26 } 27 if (!getClass().equals(obj.getClass())) { 28 return false; 29 } 30 31 AbstractEntity<?> that = (AbstractEntity<?>) obj; 32 33 return null == this.getId() ? false : this.getId().equals(that.getId()); 34 } 35 36 @Override 37 public int hashCode() { 38 int hashCode = 17; 39 40 hashCode += null == getId() ? 0 : getId().hashCode() * 31; 41 42 return hashCode; 43 } 44 45 }
BaseEntity則繼承AbstractEntity,BaseEntity作為其它實體的父類存在,BaseEntity定義了主鍵ID的生成策略。代碼如下:

1 package com.lyyzoo.data.entity; 2 3 import lombok.Data; 4 5 import javax.persistence.GeneratedValue; 6 import javax.persistence.GenerationType; 7 import javax.persistence.Id; 8 import javax.persistence.MappedSuperclass; 9 10 /** 11 * 統一定義id的entity基類. 12 * <p/> 13 * 抽象實體基類,提供統一的ID,和相關的基本功能 14 * <p/> 15 */ 16 @Data 17 @MappedSuperclass 18 @SuppressWarnings("serial") 19 public abstract class BaseEntity extends AbstractEntity<Long> { 20 21 /** 22 * id 字段 23 */ 24 @Id 25 protected Long id; 26 27 @Id 28 @GeneratedValue(strategy = GenerationType.IDENTITY) 29 public Long getId() { 30 return this.id; 31 } 32 33 public void setId(Long id) { 34 this.id = id; 35 } 36 }
spring-base.xml是基礎配置,主要配置了掃描系統的配置文件、注解等。

1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 3 xmlns="http://www.springframework.org/schema/beans" 4 xmlns:beans="http://www.springframework.org/schema/beans" 5 xmlns:context="http://www.springframework.org/schema/context" 6 xmlns:aop="http://www.springframework.org/schema/aop" 7 xmlns:tx="http://www.springframework.org/schema/tx" 8 xmlns:util="http://www.springframework.org/schema/util" 9 xmlns:mvc="http://www.springframework.org/schema/mvc" 10 xmlns:jee="http://www.springframework.org/schema/jee" 11 xmlns:jdbc="http://www.springframework.org/schema/jdbc" 12 xmlns:tool="http://www.springframework.org/schema/tool" 13 xmlns:dwr="http://www.directwebremoting.org/schema/spring-dwr" 14 xsi:schemaLocation=" 15 http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd 16 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd 17 http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd 18 http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd 19 http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd 20 http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd 21 http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee.xsd 22 http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd 23 http://www.springframework.org/schema/tool http://www.springframework.org/schema/tool/spring-tool.xsd 24 http://www.directwebremoting.org/schema/spring-dwr http://www.directwebremoting.org/schema/spring-dwr-3.0.xsd" 25 > 26 27 <description>Spring Base Config</description> 28 29 <!-- 加載config.properties --> 30 <context:property-placeholder location="classpath*:/config/*.properties" file-encoding="UTF-8" /> 31 32 <!-- 使用annotation 自動注冊bean, 並保證@Required、@Autowired的屬性被注入 --> 33 <context:component-scan base-package="com.lyyzoo"> 34 <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/> 35 <context:exclude-filter type="annotation" expression="org.springframework.web.bind.annotation.ControllerAdvice"/> 36 </context:component-scan> 37 38 <!-- 支持上傳文件 --> 39 <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"/> 40 41 </beans>
(3) lyyzoo-starter-jpa
lyyzoo-starter-jpa 目錄結構:
lyyzoo-starter-jpa集成了持久化相關的操作,配置等。
首先需要做持久化相關的配置(spring-base-jpa.xml),如數據源、SessionFactory、事務管理等。數據源使用c3p0,數據源相關配置如數據庫驅動、地址等寫到到配置文件中。配置Hibernate SessionFactory的同時,增加了JdbcTemplate。事務管理器使用Hibernate的事務管理。總的配置如下:

1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 3 xmlns="http://www.springframework.org/schema/beans" 4 xmlns:beans="http://www.springframework.org/schema/beans" 5 xmlns:tx="http://www.springframework.org/schema/tx" 6 xmlns:aop="http://www.springframework.org/schema/aop" 7 xmlns:context="http://www.springframework.org/schema/context" 8 xmlns:mvc="http://www.springframework.org/schema/mvc" 9 xmlns:util="http://www.springframework.org/schema/util" 10 xmlns:jee="http://www.springframework.org/schema/jee" 11 xmlns:jdbc="http://www.springframework.org/schema/jdbc" 12 xmlns:tool="http://www.springframework.org/schema/tool" 13 xmlns:dwr="http://www.directwebremoting.org/schema/spring-dwr" 14 xsi:schemaLocation=" 15 http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd 16 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd 17 http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd 18 http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd 19 http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd 20 http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd 21 http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee.xsd 22 http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd 23 http://www.springframework.org/schema/tool http://www.springframework.org/schema/tool/spring-tool.xsd 24 http://www.directwebremoting.org/schema/spring-dwr http://www.directwebremoting.org/schema/spring-dwr-3.0.xsd" 25 > 26 27 <description>Spring Jpa</description> 28 29 <!-- 使用C3P0 --> 30 <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> 31 <property name="driverClass" value="${jdbc.driver}"/> 32 <property name="jdbcUrl" value="${jdbc.url}"/> 33 <property name="user" value="${jdbc.username}"/> 34 <property name="password" value="${jdbc.password}"/> 35 36 <!-- default: 3 --> 37 <!-- 初始化時獲取三個連接,取值應在minPoolSize與maxPoolSize之間。--> 38 <property name="initialPoolSize" value="${c3p0.initialPoolSize:5}"/> 39 40 <!-- default: 3 --> 41 <!-- 連接池保留最小連接數--> 42 <property name="minPoolSize" value="${c3p0.minPoolSize:5}"/> 43 44 <!-- default: 15 --> 45 <!-- 連接池保留最大連接數。--> 46 <property name="maxPoolSize" value="${c3p0.maxPoolSize:15}"/> 47 48 <!-- default: 0(秒) = 永不丟棄--> 49 <!-- 最大空閑時間,600 秒內未使用則連接被丟棄。--> 50 <property name="maxIdleTime" value="${c3p0.maxIdleTime:600}"/> 51 </bean> 52 53 <!-- sessionFactory --> 54 <bean id="sessionFactory" class="org.springframework.orm.hibernate5.LocalSessionFactoryBean"> 55 <property name="dataSource" ref="dataSource" /> 56 <property name="hibernateProperties" > 57 <props> 58 <prop key="dialect">${hibernate.dialect}</prop> 59 <prop key="show_sql">${hibernate.show.sql}</prop> 60 <prop key="hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop> 61 </props> 62 </property> 63 <!-- 掃描hibernate注解實體 --> 64 <property name="packagesToScan"> 65 <list> 66 <value>com.lyyzoo.*.entity</value> 67 </list> 68 </property> 69 </bean> 70 71 <!-- jdbcTemplate --> 72 <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> 73 <property name="dataSource" ref="dataSource"/> 74 </bean> 75 <bean id="namedParameterJdbcTemplate" class="org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate"> 76 <constructor-arg ref="dataSource"/> 77 </bean> 78 <bean id="jdbcTemplateSupport" class="com.lyyzoo.data.jdbc.JdbcTemplateSupport"> 79 <property name="dataSource" ref="dataSource"/> 80 <property name="namedParameterJdbcTemplate" ref="namedParameterJdbcTemplate"/> 81 </bean> 82 83 <!-- 事務管理器 --> 84 <bean id="transactionManager" class="org.springframework.orm.hibernate5.HibernateTransactionManager"> 85 <property name="sessionFactory" ref="sessionFactory" /> 86 </bean> 87 88 <!-- 事務通知屬性 --> 89 <tx:advice id="transactionManagerAdvice" transaction-manager="transactionManager"> 90 <tx:attributes> 91 <tx:method name="get*" read-only="true" /> 92 <tx:method name="load*" read-only="true" /> 93 <tx:method name="find*" read-only="true" /> 94 <tx:method name="list*" read-only="true" /> 95 <tx:method name="page*" read-only="true" /> 96 <tx:method name="query*" read-only="true" /> 97 <tx:method name="*" propagation="REQUIRED" /> 98 </tx:attributes> 99 </tx:advice> 100 101 <!-- AOP 事務 --> 102 <aop:config proxy-target-class="true"> 103 <aop:pointcut id="serviceMethod" expression="execution(* com.lyyzoo..*Service.*(..))"/> 104 <aop:advisor pointcut-ref="serviceMethod" advice-ref="transactionManagerAdvice"/> 105 </aop:config> 106 107 <!-- 掃描注解 --> 108 <context:component-scan base-package="com.lyyzoo" /> 109 110 </beans>
然后在com.lyyzoo.data.domain包下,Page封裝了分頁相關的屬性,如當前頁數據、頁碼、每頁大小、總頁數等。com.lyyzoo.data.util包下,Sqls封裝了操作sql語句的工具,比如根據傳入的查詢語句,返回查詢總數的sql語句。在com.lyyzoo.data.jdbc包下,JdbcTemplateSupport封裝了比較復雜的查詢,比如根據傳入的參數、分頁條件等,自動查詢數據、總數並封裝到Page里返回。com.lyyzoo.data.dao包下,SimpleDao封裝了基於Hibernate SessionFactory的簡單的增刪改查操作,如save(),get()等方法。dao包下,BaseDao繼承SimpleDao,並代理了JdbcTemplateSupport,使得BaseDao具有SimpleDao和JdbcTemplateSupport的功能,BaseDao則作為其它dao的一個父類存在。最后,在com.lyyzoo.service包下,BaseService代理了BaseDao,進行了進一步的封裝,BaseService是其它service類的父類,其它service就可以直接調用save、get、page等內置方法。
(4) lyyzoo-starter-web
lyyzoo-starter-web自然跟web相關,在com.lyyzoo.web包下,BaseController作為controller類的父類,主要封裝了返回結果集等信息。還有web相關配置,如視圖解析器等內容:

1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 3 xmlns="http://www.springframework.org/schema/beans" 4 xmlns:beans="http://www.springframework.org/schema/beans" 5 xmlns:tx="http://www.springframework.org/schema/tx" 6 xmlns:aop="http://www.springframework.org/schema/aop" 7 xmlns:context="http://www.springframework.org/schema/context" 8 xmlns:mvc="http://www.springframework.org/schema/mvc" 9 xmlns:task="http://www.springframework.org/schema/task" 10 xmlns:util="http://www.springframework.org/schema/util" 11 xmlns:jee="http://www.springframework.org/schema/jee" 12 xmlns:jdbc="http://www.springframework.org/schema/jdbc" 13 xmlns:tool="http://www.springframework.org/schema/tool" 14 xmlns:dwr="http://www.directwebremoting.org/schema/spring-dwr" 15 xsi:schemaLocation=" 16 http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd 17 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd 18 http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd 19 http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd 20 http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd 21 http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd 22 http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.2.xsd 23 http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee.xsd 24 http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd 25 http://www.springframework.org/schema/tool http://www.springframework.org/schema/tool/spring-tool.xsd 26 http://www.directwebremoting.org/schema/spring-dwr http://www.directwebremoting.org/schema/spring-dwr-3.0.xsd" 27 > 28 29 <description>Spring Web</description> 30 31 <!-- 加載config.properties --> 32 <context:property-placeholder location="classpath*:/config/*.properties" file-encoding="UTF-8" /> 33 34 <!-- 掃描Controller以及ControllerAdvice --> 35 <context:component-scan base-package="com.lyyzoo" use-default-filters="false"> 36 <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/> 37 <context:include-filter type="annotation" expression="org.springframework.web.bind.annotation.ControllerAdvice"/> 38 </context:component-scan> 39 40 <!-- 靜態資源映射 --> 41 <mvc:resources location="/static/" mapping="/static/**"/> 42 43 <!-- 容器默認的DefaultServletHandler處理 所有靜態內容與無RequestMapping處理的URL--> 44 <mvc:default-servlet-handler /> 45 46 <!-- 支持@Controller注解 --> 47 <mvc:annotation-driven /> 48 49 <!-- 視圖解析器 --> 50 <bean id="jspViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver"> 51 <property name="prefix" value="/WEB-INF/view"/> 52 <property name="suffix" value=".jsp"/> 53 </bean> 54 55 </beans>
(5) 類結構圖
類結構圖參考《底層類結構.vsd》
五、數據庫與實體設計
在開始開發一個系統之前,首先需要做的就是根據需求分析設計系統的實體對象以及對應的數據庫表結構,這是開發的基礎。
根據前面的需求分析設計的功能模塊,實體對象可以分為5個模塊,分別是系統模塊(system)、基礎模塊(base)、采購模塊(purchase)、銷售模塊(sale)、庫存模塊(stock)。下面是實體清單:
有了清單之后,利用PowerDesigner進行數據庫物理模型設計。由於擁有對數據庫的完全控制權,所以不對表設置約束,所有的約束在程序代碼中進行控制。下面列出各個實體的屬性即對應的表,具體可參考《數據庫物理模型.pdm》。物理模型設計完成后,創建名為gpss的數據庫,然后創建各個表。
數據庫模型:
六、系統功能實現
1.創建工程
需求分析做完了,技術沒問題,底層架構也設計好了,數據庫設計好了,前面的所有准備工作做完了,下面就要進行燃氣管進銷存系統的編碼實現了。首先要做的工作就是創建工程,項目名擬為gpss,即燃氣管進銷存(Gas Purchase Sale Stock)的縮寫,工程名則為lyyzoo-gpss。
在IDEA中創建lyyzoo-gpss的maven工程,繼承lyyzoo。同時,在lyyzoo-gpss下創建兩個子模塊,分別為lyyzoo-gpss-base和lyyzoo-gpss-web,base模塊包含了系統的dao、entity、service等層次,主要為java文件;web則包含了controller層、jsp、js等web相關資源文件。
lyyzoo-gpss目錄結構:
lyyzoo-gpss > pom.xml:

1 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 2 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 3 <modelVersion>4.0.0</modelVersion> 4 <parent> 5 <groupId>com.lyyzoo</groupId> 6 <artifactId>lyyzoo</artifactId> 7 <version>1.0-SNAPSHOT</version> 8 </parent> 9 <groupId>com.lyyzoo.gpss</groupId> 10 <artifactId>lyyzoo-gpss</artifactId> 11 <name>lyyzoo :: gpss</name> 12 <packaging>pom</packaging> 13 14 <modules> 15 <module>lyyzoo-gpss-base</module> 16 <module>lyyzoo-gpss-web</module> 17 </modules> 18 19 <profiles> 20 <!-- 開發環境 --> 21 <profile> 22 <id>dev</id> 23 <activation> 24 <property> 25 <name>env</name> 26 <value>dev</value> 27 </property> 28 </activation> 29 </profile> 30 <!-- 線上環境 --> 31 <profile> 32 <id>online</id> 33 <activation> 34 <property> 35 <name>env</name> 36 <value>online</value> 37 </property> 38 </activation> 39 </profile> 40 </profiles> 41 <build> 42 <plugins> 43 <plugin> 44 <groupId>com.juvenxu.portable-config-maven-plugin</groupId> 45 <artifactId>portable-config-maven-plugin</artifactId> 46 <version>1.1.5</version> 47 <executions> 48 <execution> 49 <goals> 50 <goal>replace-package</goal> 51 </goals> 52 </execution> 53 </executions> 54 <configuration> 55 <portableConfig>src/main/resources/portable/config-${env}.xml</portableConfig> 56 </configuration> 57 </plugin> 58 </plugins> 59 </build> 60 61 </project>
lyyzoo-gpss-base主要是dao層、service層、model層的集成,所以需要依賴於底層lyyzoo-starter-jpa、lyyzoo-starter-web。
lyyzoo-gpss-base > pom.xml:

1 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 2 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 3 <modelVersion>4.0.0</modelVersion> 4 <parent> 5 <groupId>com.lyyzoo.gpss</groupId> 6 <artifactId>lyyzoo-gpss</artifactId> 7 <version>1.0-SNAPSHOT</version> 8 </parent> 9 <artifactId>lyyzoo-gpss-base</artifactId> 10 <name>lyyzoo :: gpss :: base</name> 11 <packaging>jar</packaging> 12 13 <dependencies> 14 <dependency> 15 <groupId>com.lyyzoo</groupId> 16 <artifactId>lyyzoo-starter-jpa</artifactId> 17 </dependency> 18 <dependency> 19 <groupId>com.lyyzoo</groupId> 20 <artifactId>lyyzoo-starter-web</artifactId> 21 </dependency> 22 </dependencies> 23 24 </project>
lyyzoo-gpss-web是web相關,是controller層所在。依賴於lyyzoo-gpss-base、lyyzoo-starter-base等。
lyyzoo-gpss-web > pom.xml:

1 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 2 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> 3 <modelVersion>4.0.0</modelVersion> 4 <parent> 5 <groupId>com.lyyzoo.gpss</groupId> 6 <artifactId>lyyzoo-gpss</artifactId> 7 <version>1.0-SNAPSHOT</version> 8 </parent> 9 <artifactId>lyyzoo-gpss-web</artifactId> 10 <name>lyyzoo :: gpss :: web</name> 11 <packaging>war</packaging> 12 13 <dependencies> 14 <dependency> 15 <groupId>com.lyyzoo.gpss</groupId> 16 <artifactId>lyyzoo-gpss-base</artifactId> 17 <version>${project.version}</version> 18 </dependency> 19 <dependency> 20 <groupId>com.lyyzoo</groupId> 21 <artifactId>lyyzoo-starter-base</artifactId> 22 </dependency> 23 <dependency> 24 <groupId>com.lyyzoo</groupId> 25 <artifactId>lyyzoo-starter-jpa</artifactId> 26 </dependency> 27 <dependency> 28 <groupId>com.lyyzoo</groupId> 29 <artifactId>lyyzoo-starter-web</artifactId> 30 </dependency> 31 <dependency> 32 <groupId>com.lyyzoo</groupId> 33 <artifactId>lyyzoo-starter-test</artifactId> 34 </dependency> 35 36 37 </dependencies> 38 39 40 <build> 41 <finalName>gpss</finalName> 42 <outputDirectory>src/main/webapp/WEB-INF/classes</outputDirectory> 43 </build> 44 45 </project>
2.系統配置
工程建好后,首要要做的就是系統的配置工作了,如web.xml,這應該算是web項目的起點了。進入lyyzoo-gpss-web/src/main/webapp/WEB-INF/web.xml,進行web的配置,主要的一些配置有加載系統的配置文件、Spring、字符過濾器、SpringMVC等配置。
一些基礎的配置如下:

1 <?xml version="1.0" encoding="UTF-8"?> 2 <web-app xmlns="http://java.sun.com/xml/ns/javaee" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 5 http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" 6 version="3.0"> 7 8 <display-name>lyyzoo :: gpss</display-name> 9 10 <!-- 加載配置文件 --> 11 <context-param> 12 <param-name>contextConfigLocation</param-name> 13 <param-value>classpath*:/spring/spring-base*.xml</param-value> 14 </context-param> 15 16 <!-- Spring --> 17 <listener> 18 <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> 19 </listener> 20 21 <!-- 編碼過濾器 --> 22 <filter> 23 <filter-name>encodingFilter</filter-name> 24 <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> 25 <init-param> 26 <param-name>encoding</param-name> 27 <param-value>UTF-8</param-value> 28 </init-param> 29 <init-param> 30 <param-name>forceEncoding</param-name> 31 <param-value>true</param-value> 32 </init-param> 33 </filter> 34 <filter-mapping> 35 <filter-name>encodingFilter</filter-name> 36 <url-pattern>/*</url-pattern> 37 </filter-mapping> 38 39 <!-- 訪問控制 --> 40 <filter> 41 <filter-name>VisitFilter</filter-name> 42 <filter-class>com.lyyzoo.gpss.filter.VisitFilter</filter-class> 43 </filter> 44 <filter-mapping> 45 <filter-name>VisitFilter</filter-name> 46 <url-pattern>/admin/*</url-pattern> 47 </filter-mapping> 48 49 <!-- Spring MVC --> 50 <servlet> 51 <servlet-name>SpringMVC</servlet-name> 52 <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> 53 <init-param> 54 <param-name>contextConfigLocation</param-name> 55 <param-value>classpath*:/spring/spring-web*.xml</param-value> 56 </init-param> 57 <load-on-startup>1</load-on-startup> 58 </servlet> 59 <servlet-mapping> 60 <servlet-name>SpringMVC</servlet-name> 61 <url-pattern>/</url-pattern> 62 </servlet-mapping> 63 64 <!-- 錯誤頁面 --> 65 <error-page> 66 <error-code>404</error-code> 67 <location>/error/404</location> 68 </error-page> 69 <error-page> 70 <error-code>500</error-code> 71 <location>/error/500</location> 72 </error-page> 73 <error-page> 74 <exception-type>java.lang.Throwable</exception-type> 75 <location>/error/500</location> 76 </error-page> 77 78 <!-- 首頁 --> 79 <welcome-file-list> 80 <welcome-file>/</welcome-file> 81 </welcome-file-list> 82 83 </web-app>
接着,配置系統將會用到的一些屬性,如JDBC驅動、數據庫用戶名和密碼等。在lyyzoo-gpss-web/src/main/resources/config下,創建config.properties配置文件,這個配置文件中的屬性將會被底層spring配置的文件所引用。
比如JDBC的屬性:

1 #################################### 2 # DATABASE 3 #################################### 4 # local_db 5 jdbc.driver=net.sf.log4jdbc.DriverSpy 6 jdbc.url=jdbc:log4jdbc:mysql://localhost:3306/gpss?useUnicode=true&characterEncoding=utf-8&autoReconnect=true&failOverReadOnly=false 7 jdbc.username=root 8 jdbc.password=root 9 10 # 初始化連接 11 c3p0.initialPoolSize=5 12 # 連接池保留最小連接數 13 c3p0.minPoolSize=5 14 # 連接池保留最大連接數 15 c3p0.maxPoolSize=15 16 # 最大空閑時間 17 c3p0.maxIdleTime=600 18 19 #hibernate 20 hibernate.dialect=org.hibernate.dialect.MySQL5Dialect 21 hibernate.show.sql=false 22 hibernate.hbm2ddl.auto=update
但是上面的配置只是本機的一個開發環境,如果我將項目發布到生產環境,那就至少需要重新修改數據庫地址、用戶名和密碼。這樣是比較麻煩的,所以,在lyyzoo-gpss-web/src/main/portable下創建兩個xml文件,分別為開發環境和生產環境的:config-dev.xml和config-online.xml。
config-online.xml:

1 <?xml version="1.0" encoding="utf-8" ?> 2 3 <portable-config> 4 <config-file path="WEB-INF/classes/config/config.properties"> 5 6 <!-- JDBC --> 7 <replace key="jdbc.driver"><![CDATA[com.mysql.jdbc.Driver]]></replace> 8 <replace key="jdbc.url"><![CDATA[jdbc:mysql://192.168.1.91:30112/fff2f025c2b04?useUnicode=true&characterEncoding=utf-8]]></replace> 9 <replace key="jdbc.username">a6564a1169d94</replace> 10 <replace key="jdbc.password">d3e6d1aea5e04</replace> 11 12 <!-- hibernate --> 13 <replace key="hibernate.show.sql">false</replace> 14 <replace key="hibernate.hbm2ddl.auto">none</replace> 15 16 <!-- debug --> 17 <replace key="app.debug">false</replace> 18 <replace key="app.env">online</replace> 19 <replace key="logback.level">INFO</replace> 20 <replace key="jdbc.resultsettable">ERROR</replace> 21 22 23 </config-file> 24 </portable-config>
然后配置一個“不同環境打包”的maven插件——“portable-config-maven-plugin”,通過該插件,就可以在打包的時候加上需要打包的環境,例如指定online環境,在打包時就會將config-online.xml中的屬性替換到config.properties里,這樣一來就不必我們手動去替換了。配置好之后,我們在打包時可以使用命令[mvn clean package –Denv=online]打包線上環境的war包。
maven環境配置,在lyyzoo-gpss > pom.xml中配置兩個環境:

1 <profiles> 2 <!-- 開發環境 --> 3 <profile> 4 <id>dev</id> 5 <activation> 6 <property> 7 <name>env</name> 8 <value>dev</value> 9 </property> 10 </activation> 11 </profile> 12 <!-- 線上環境 --> 13 <profile> 14 <id>online</id> 15 <activation> 16 <property> 17 <name>env</name> 18 <value>online</value> 19 </property> 20 </activation> 21 </profile> 22 </profiles>
不同環境打包插件(portable-config-maven-plugin)的配置:

1 <build> 2 <plugins> 3 <plugin> 4 <groupId>com.juvenxu.portable-config-maven-plugin</groupId> 5 <artifactId>portable-config-maven-plugin</artifactId> 6 <version>1.1.5</version> 7 <executions> 8 <execution> 9 <goals> 10 <goal>replace-package</goal> 11 </goals> 12 </execution> 13 </executions> 14 <configuration> 15 <portableConfig>src/main/resources/portable/config-${env}.xml</portableConfig> 16 </configuration> 17 </plugin> 18 </plugins> 19 </build>
3.模塊分層
3.1 lyyzoo-gpss-base
工程建好后,創建包的結構。按照一般的分層方式,分為dao層、entity層、service層,同時,每層下按模塊划分為system、base、purchase、sale、stock。然后在entity下根據表設計創建實體類。
lyyzoo-gpss-base 目錄結構:
3.2 lyyzoo-gpss-web
然后是lyyzoo-gpss-web模塊,該模塊主要是controller層,以及靜態資源文件、jsp文件等。com.lyyzoo.gpss.web作為controller層的包,同樣,在web下按系統模塊划分。
lyyzoo-gpss-web 目錄結構:
3.3 靜態資源文件
lyyzoo-gpss-web/src/main/webapp/static作為靜態文件的根目錄,static/lib目錄作為三方類庫的根目錄,如ExtJs、jQuery、其它的插件等。static/css是系統css文件的根目錄;static/img是圖片的根目錄;static/js是系統js文件根目錄,/js下同樣按模塊划分。
靜態資源文件目錄結構:
3.4 JSP文件
jsp文件不能直接讓用戶訪問,需要放到/WEB-INF下,與配置的spring視圖解析器相對應,所有的jsp文件放到/WEB-INF/view目錄下,view目錄下按模塊划分,index.jsp是系統的登錄頁面。/WEB-INF/layout/目錄下,將jsp中需要引入的一些資源等做了整合,如ExtJs的文件、meta描述信息、taglib等,整合后,jsp中如果需要引入整合jsp即可,可減少很多重復的工作。
taglib.jsp中引入了標簽和設置了資源的路徑:

1 <%@ page contentType="text/html;charset=UTF-8" language="java" %> 2 3 <%-- 引入標簽 --%> 4 <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> 5 <%@taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %> 6 <%@taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %> 7 <%@taglib prefix="sf" uri="http://www.springframework.org/tags/form" %> 8 9 <%-- 資源路徑 --%> 10 <c:set var="CTX" value="${pageContext.request.contextPath}" /> 11 <c:set var="STATIC_CTX_URL" value="${CTX}/static" /> 12 <c:set var="LIB" value="${STATIC_CTX_URL}/lib" /> 13 <c:set var="JS" value="${STATIC_CTX_URL}/js"/> 14 <c:set var="CSS" value="${STATIC_CTX_URL}/css"/> 15 <c:set var="IMG" value="${STATIC_CTX_URL}/img"/>
meta.jsp中主要設置了一些meta描述信息和ICO圖標:

1 <%@ page contentType="text/html;charset=UTF-8" language="java" %> 2 <%@ include file="/WEB-INF/layout/taglib.jsp" %> 3 4 <meta charset="utf-8"> 5 <meta http-equiv="X-UA-Compatible" content="IE=9,chrome=1"> 6 7 <meta name="description" content=""> 8 <meta name="author" content=""> 9 <meta name="renderer" content="webkit"> 10 <%-- 圖標 --%> 11 <link type="image/x-icon" href="${IMG}/favicon.ico" rel="icon">
extjs-neptune.jsp則引入了ExtJs相關的css和js文件,以及jQuery等:

1 <%@ page contentType="text/html;charset=UTF-8" language="java" %> 2 <%@ include file="/WEB-INF/layout/taglib.jsp" %> 3 4 <link rel="stylesheet" type="text/css" href="${LIB}/ext/4.2.2/theme/ext-theme-neptune/ext-theme-neptune-all.css"/> 5 <link rel="stylesheet" type="text/css" href="${LIB}/ext/4.2.2/icons/icon.css"/> 6 7 <script type="text/javascript" src="${LIB}/ext/4.2.2/ext-all.js"></script> 8 <script type="text/javascript" src="${LIB}/ext/4.2.2/locale/ext-lang-zh_CN.js"></script> 9 <script type="text/javascript" src="${LIB}/jquery/2.1.1/jquery.js"></script> 10 <script type="text/javascript" src="${JS}/Global.js"></script> 11 12 <script type="text/javascript"> 13 window.CTX = "${CTX}"; 14 window.STATIC_CTX_URL = "${STATIC_CTX_URL}"; 15 window.LIB = "${LIB}"; 16 window.JS = "${JS}"; 17 window.CSS = "${CSS}"; 18 window.IMG = "${IMG}"; 19 </script>
WEB-INF目錄結構:
3.4 登錄實現舉例
首先創建一個BaseController,BaseController繼承底層的BaseController,增加了HttpSession,以及獲取當前登錄用戶的方法,這樣其它的controller繼承該BaseController后,就可以非常方便的獲得當前session和登錄用戶了。
BaseController代碼如下:

1 package com.lyyzoo.gpss.web; 2 3 import com.lyyzoo.gpss.entity.system.User; 4 import org.springframework.beans.factory.annotation.Autowired; 5 6 import javax.servlet.http.HttpSession; 7 8 /** 9 * 10 * <p> 11 * 12 * @author bojiangzhou 13 * @date 2017-04-02 14 */ 15 public class BaseController extends com.lyyzoo.web.BaseController { 16 17 @Autowired 18 protected HttpSession session; 19 20 public User getCurrentUser(){ 21 return (User) session.getAttribute("currentUser"); 22 } 23 24 public Long getCurrentUserId(){ 25 return getCurrentUser().getId(); 26 } 27 28 public String getCurrentUserAccount(){ 29 return getCurrentUser().getAccount(); 30 } 31 32 }
創建HomeController作為登錄和主頁的處理器。主要包含的方法有訪問登錄頁面,訪問登錄后的主頁,以及登錄處理等。Controller需要加上@Controller標注該類為controller,使用@RequestMapping()支持訪問rest形式的地址訪問。HomeController中注入UserService,用於處理用戶登錄相關的業務。
用戶進入登錄界面,jsp頁面以<img src=” ${CTX}/vcode”>的形式請求驗證碼,驗證碼使用工具類生成,以流的形式輸出,生成的驗證碼保存到session中。用戶輸入登錄賬號、密碼和驗證碼登錄系統。首先前台會檢測輸入是否為空等,傳到后台,從session中取出驗證碼判斷驗證碼是否正確,不正確則刷新驗證碼並且需要用戶重新輸入驗證碼。驗證碼通過后,使用登錄賬號和密碼查找數據庫,如果有,則將該用戶保存到session中,跳轉到管理頁面,登錄成功。否則提示用戶名或密碼錯誤。
HomeController代碼如下:

1 package com.lyyzoo.gpss.web; 2 3 import com.lyyzoo.gpss.entity.system.User; 4 import com.lyyzoo.gpss.service.system.UserService; 5 import com.lyyzoo.gpss.util.VCodeGenerator; 6 import com.lyyzoo.util.Cryptos; 7 import com.lyyzoo.util.Strings; 8 import org.springframework.beans.BeanUtils; 9 import org.springframework.beans.factory.annotation.Autowired; 10 import org.springframework.stereotype.Controller; 11 import org.springframework.web.bind.annotation.PathVariable; 12 import org.springframework.web.bind.annotation.RequestMapping; 13 import org.springframework.web.bind.annotation.RequestMethod; 14 15 import javax.imageio.ImageIO; 16 import javax.servlet.http.HttpServletResponse; 17 import javax.servlet.http.HttpSession; 18 import java.awt.image.BufferedImage; 19 import java.io.IOException; 20 21 /** 22 * <p> 23 * 24 * @author bojiangzhou 25 * @date 2017-03-29 26 */ 27 @Controller 28 @RequestMapping("") 29 public class HomeController extends BaseController { 30 31 @Autowired 32 private UserService userService; 33 34 /** 35 * 到首頁/登錄頁面 36 */ 37 @RequestMapping(value = {"", "/", "/index", "/login"}) 38 public String index(){ 39 return "/index"; 40 } 41 42 /** 43 * 管理員主頁 44 */ 45 @RequestMapping("/admin/home") 46 public String toHome(){ 47 return "/home/home"; 48 } 49 50 /** 51 * 登錄 52 */ 53 @RequestMapping(value = "/login", method = RequestMethod.POST) 54 public String login(String account, String password, String vcode, HttpSession session){ 55 String redirect = REDIRECT("/login"); 56 //基本驗證 57 if(Strings.isNullOrEmpty(account)){ 58 session.setAttribute("errorMsg", "賬號必須填寫!"); 59 return redirect; 60 } 61 if(Strings.isNullOrEmpty(password)){ 62 session.setAttribute("errorMsg", "密碼必須填寫!"); 63 return redirect; 64 } 65 if(Strings.isNullOrEmpty(vcode)){ 66 session.setAttribute("errorMsg", "驗證碼必須填寫!"); 67 return redirect; 68 } 69 //驗證碼 70 String sessionVcode = (String) session.getAttribute("vcode"); 71 if(!vcode.equalsIgnoreCase(sessionVcode)){ 72 session.setAttribute("errorMsg", "驗證碼錯誤!"); 73 return redirect; 74 } 75 //驗證用戶名和密碼 76 password = Cryptos.encryptMd5(password); 77 User loginUser = userService.login(account, password); 78 if(loginUser == null){ 79 session.setAttribute("errorMsg", "賬號或密碼錯誤!"); 80 return redirect; 81 } 82 if(loginUser.getIsLocked() == User.IsLocked.YES){ 83 session.setAttribute("errorMsg", "賬號已鎖定,不能登錄!"); 84 return redirect; 85 } 86 87 //保存到session的時候清除密碼 88 User currentUser = new User(); 89 BeanUtils.copyProperties(loginUser, currentUser); 90 currentUser.setPassword(null); 91 92 //登錄成功 93 session.setAttribute("currentUser", currentUser); 94 95 return REDIRECT("/admin/home"); 96 } 97 98 /** 99 * 獲取驗證碼 100 */ 101 @RequestMapping("/vcode") 102 public void getVCode(HttpSession session, HttpServletResponse response) throws IOException { 103 //創建驗證碼生成器對象 104 VCodeGenerator vcGenerator = new VCodeGenerator(); 105 //生成驗證碼 106 String vcode = vcGenerator.generatorVCode(); 107 //將驗證碼保存在session域中,以便判斷驗證碼是否正確 108 session.setAttribute("vcode", vcode); 109 //生成驗證碼圖片 110 BufferedImage vImg = vcGenerator.generatorRotateVCodeImage(vcode, true); 111 //輸出圖像 112 ImageIO.write(vImg, "gif", response.getOutputStream()); 113 } 114 115 /** 116 * 退出系統 117 */ 118 @RequestMapping("/logoff") 119 public String logoff(HttpSession session){ 120 session.invalidate(); 121 return REDIRECT("/"); 122 } 123 124 @RequestMapping("/function") 125 public String function(){ 126 return "/home/function"; 127 } 128 129 @RequestMapping("/welcome") 130 public String welcome(){ 131 return "/home/welcome"; 132 } 133 134 /** 135 * 錯誤頁面 136 * @param code 137 * @return 138 */ 139 @RequestMapping("/error/{code}") 140 public String error(@PathVariable String code) { 141 return "/error/" + code; 142 } 143 144 145 146 }
UserService中根據用戶名和密碼獲取用戶:

1 package com.lyyzoo.gpss.service.system; 2 3 @Service 4 public class UserService extends BaseService<User> { 5 @Autowired 6 private UserDao userDao; 7 /** 8 * 獲取登錄用戶 9 */ 10 public User login(String account, String password){ 11 Map<String, Object> filter = new HashMap<>(); 12 filter.put("account", account); 13 filter.put("password", password); 14 filter.put("state", Applications.Flag.YES); 15 16 User loginUser = get(filter); 17 return loginUser; 18 } 19 }
七、系統的調試與部署
1.測試
系統開發完成后,首先需要在本地整體測試,從登錄開始,每個模塊,每個功能,每個流程具體的去測試。
首先測試如果未登錄,用戶是不能訪問管理頁面的,直接在地址欄輸入訪問地址看是否跳轉到登錄頁面。然后至少測試各個角色相關的賬號登錄是否正常,登錄后,每個角色擁有的菜單是否顯示正常。
其它模塊的測試,使用各個角色對應的賬號,登錄系統,進行相應功能的測試。如管理員進入系統錄入基礎數據,商品信息、倉庫信息等。采購管理員錄入供應商信息,錄入采購訂單,提交審核。銷售管理員錄入客戶信息,錄入銷售訂單,提交審核。庫存管理員審核采購訂單,審核通過,則庫存增加;審核銷售訂單,審核通過,則庫存減少。查看庫存信息,相應的操作之后,庫存量是否正確。測試結果可查看系統測試截圖。
系統容錯性測試,主要是測試輸入一些錯誤的數據類型以及超出范圍的數值測試系統在異常條件下的行為。系統在這方面做得比較好,如果用戶輸入了一些非法的數據,會立即提醒用戶輸入正確的數據。首先會在前台判斷用戶輸入的數據的合法性、是否必須輸入等,數據傳到后台后,還會在代碼里判斷一次數據是否正確,才會保存到數據庫。而系統使用的Jdbc也能在一定程度上防止SQL注入等問題。如果系統發生一些無法預測的異常,也會以友好的界面提示用戶,以便技術員及時維護系統。
總體來說,整個的測試過程比較順利,也存在一些小問題,就立即修復了。功能全部實現了,該系統能滿足一個基本的進銷存流程,以后也還可以擴展。
2.部署
我這里使用磨泊雲來部署項目,磨泊雲使用簡單且在一定限度內免費,部署測試比較合適。首先在磨泊雲上創建名為gpss的Java應用,接着創建mysql服務,並將其綁定到該java應用,復制數據庫連接到配置文件中。導出本地的gpss數據庫,導入到創建的mysql應用里。然后在IDEA中使用mvn clean package –Denv=online命令打包線上環境的war包,將war包發布到磨泊雲上。啟動項目,然后訪問,測試,一些都正常。可訪問域名http://gpss.butterfly.mopaasapp.com/查看,由於沒處理好ext的兼容性問題,建議使用谷歌瀏覽器查看。后面再學學如何部署到像阿里雲等雲上。
八、總結
通過自己一步步去設計完成這個燃氣管進銷存系統,讓我對軟件的架構、設計、框架、編碼、以及各種工具的使用更加熟練,熟悉了軟件的開發流程。這個系統更是大學四年所學知識的一個產物,從拿到論文命題開始,理解命題,查閱相關資料,進行需求分析,設計功能模塊,設計數據庫;然后結合自己在實習期的工作經驗以及公司的架構設計,搭建了一個自己的底層。在這個底層的基礎上進行系統的開發。
經過近一個月的畢業設計,掌握了軟件開發各個方面的相關知識,熟悉了整個流程,也檢驗了自己大學四年的知識水平。顯然也還是有很多不足的,比如該系統中雖然使用SSH框架,但其框架的原理實現上還有很多不明白。個人認為學習一定要知其然也要知其所以然,尤其對於技術,需要去了解它的底層原理,才能提高自己的能力。這些就在以后的工作中去逐漸提高。
寫到這里就基本完了,大學四年的最后一篇博客,以后就是在工作中去學習了。
很開心,要離開學校了,可以去工作找money了;很憂傷,要離開學校了,一生中可能最舒適的時光就是大學時光了。
我很喜歡我的學校 —— 西南大學,坐落於縉雲山下,環境優美、美女如雲,哈哈!
九、附件
github地址:https://github.com/bojiangzhou/lyyzoo-gpss
論文地址:https://download.csdn.net/download/u013244234/10281005
最后,系統開發相關文件分享出來:燃氣管網設備進銷存系統
壓縮包目錄如下: