一個SSM(Spring+SpringMVC+Mybatis)+jQuery EasyUI開發的ERP系統
生產管理ERP系統
這是一個生產管理ERP系統。依託科技計劃重點專案“裝備物聯及生產管理系統研發”,專案研發裝備物聯以及生產管理的系統,主要包括:計劃進度、裝置管理、工藝監控、物料監控、人員監控、質量監控、系統管理7大模組。專案原始碼共享在github上面:http://github.com/megagao/production_ms。
專案技術架構(Spring+SpringMVC+Mybatis)
- Maven
- Spring(IOC DI AOP 宣告式事務處理)
- SpringMVC(支援Restful風格)
- Hibernate Validator(引數校驗)
- Mybatis(最少配置方案)
- shiro許可權控制,結合ajax實現了非同步認證與非同步授權,同時實現了細粒度的許可權動態分配(到按鈕級別);添加了shiro session過期的登入跳轉
- jQuery EasyUI開發前端頁面,利用jQuery檔案上傳外掛實現拖拽上傳的效果並對檔案型別、大小、數量進行控制;利用search-box實現查詢功能
- Druid(資料來源配置 sql防注入 sql效能監控)
- 統一的異常處理
- JSP JSTL JavaScript
- kindeditor富文字編輯器,處理圖片上傳和富文字編輯
系統架構
資料庫設計(詳見sql檔案)
軟體執行截圖
- 登入介面
登入可使用賬號:22,密碼:22的超級管理員登入,若密碼輸錯,下次登入需輸入驗證碼。
- 執行介面
超級管理員可顯示系統管理模組進行系統許可權分配與管理,其他角色可檢視除系統管理外的剩餘模組的資訊(包括下載附件、檢視圖片等),但是隻能維護該角色對應許可權內的資訊。
左邊功能搜尋欄可進行功能模糊查詢。
- 圖片上傳
圖片上傳的配置請檢視文件尾部的註釋,圖片大小要求不能超過1M,支援jpg、png等多種格式的圖片,上傳成功後可在相應的展示欄進行回顯。
- 檔案上傳
檔案上傳使用了一個開源的jQuery檔案上傳外掛,可以在common.js裡面修改上傳檔案的引數,包括上傳個數,支援的檔案型別等,配置資訊如下:
1 2 3 4 5 6 |
url:"file/upload", maxFileCount: 5, //上傳檔案個數(多個時修改此處 returnType: 'json', //服務返回資料 allowedTypes: 'doc,docx,excel,sql,txt,ppt,pdf', //允許上傳的檔案式 showDone: false, //是否顯示"Done"(完成)按鈕 showDelete: true, //是否顯示"Delete"(刪除)按鈕 |
檔案上傳的介面如下:
- 富文字編輯
本系統採用了開源的KindEditor富文字編輯器,它是一套線上HTML編輯器,主要用於讓使用者在網站上獲得所見即所得編輯效果。KindEditor把傳統的多行文字輸入框(textarea)替換為視覺化的富文字輸入框。
KindEditor主要特點
- 快速:體積小,載入速度快
- 開源:開放原始碼,高水平,高品質
- 底層:內建自定義 DOM 類庫,精確操作 DOM
- 擴充套件:基於外掛的設計,所有功能都是外掛,可根據需求增減功能
- 風格:修改編輯器風格非常容易,只需修改一個 CSS 檔案
- 相容:支援大部分主流瀏覽器,比如 IE、Firefox、Safari、Chrome、Opera
- 關聯資訊
關聯物件的資訊,點選以彈窗的形式顯示,若具有該模組對應的修改許可權,則也可在此進行資訊維護。
- search-box查詢
可以在右上角的search-box選擇查詢條件,輸入關鍵字進行對應資訊的模糊查詢。
- session過期跳轉登入
使用者登入後,會建立相應的session,系統預設過期時間為10分鐘,若需更改,可在applicationContext-shiro.xml配置檔案中,更改如下配置。
<!-- 會話管理器 -->
<bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
<!-- session的失效時長,單位毫秒 ,這裡設定為10分鐘-->
<property name="globalSessionTimeout" value="600000"/>
<!-- 刪除失效的session -->
<property name="deleteInvalidSessions" value="true"/>
<!-- 指定本系統sessionId, 預設為: JSESSIONID 問題: 與Servlet容器名衝突, 如Jetty, Tomcat等預設JSESSIONID,
當跳出shiro Servlet時如Error-page容器會為JSESSIONID重新分配值導致登入會話丟失! -->
<property name="sessionIdCookie" ref="sessionIdCookie"/>
</bean>
若session過期,則應跳轉登入介面重新登入。系統採用的方式是設定一個sessionfilter,如下:
public class SessionFilter implements Filter {
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException,
ServletException {
HttpServletRequest request = (HttpServletRequest) servletRequest;
HttpServletResponse response = (HttpServletResponse) servletResponse;
if (!SecurityUtils.getSubject().isAuthenticated()) {
//判斷session裡是否有使用者資訊,且是否為ajax請求,如果是ajax請求響應頭會有,x-requested-with
if (request.getHeader("x-requested-with") != null
&& request.getHeader("x-requested-with").equalsIgnoreCase("XMLHttpRequest")) {
response.setHeader("session-status", "timeout");//在響應頭設定session狀態
}
}
filterChain.doFilter(request, servletResponse);
}
@Override
public void destroy() {
// TODO Auto-generated method stub
}
@Override
public void init(FilterConfig arg0) throws ServletException {
// TODO Auto-generated method stub
}
}
並在web.xml中配置該filter。當session過期時, 在響應頭設定session狀態為timeout,然後採用全域性的ajax事件對session狀態進行判斷,跳轉到登入頁面。該事件定義在common.js中,如下:
//全域性ajax事件,處理session過期跳轉登入
$.ajaxSetup({
complete:function(XMLHttpRequest,sessionStatus){
var sessionstatus = XMLHttpRequest.getResponseHeader("session-status");
if(sessionstatus=="timeout"){
$.messager.alert('提示資訊', "登入超時!請重新登入!", 'info',function(){
window.location.href = 'login';
});
}
}
});
關於這部分的詳細內容請參考我的一篇部落格:利用filter和全域性ajax事件實現shiro session過期登入跳轉
- 動態許可權控制
本系統採用經典的許可權模型,即RBAC(Role-Based Access Control )基於角色的訪問控制,即使用者通過角色與許可權進行關聯。模型用到5張表:使用者表、角色表、許可權表、使用者角色表、角色許可權表。簡單地說,一個使用者擁有若干角色,每一個角色擁有若干許可權。這樣,就構造成“使用者-角色-許可權”的授權模型。在這種模型中,使用者與角色之間,角色與許可權之間,一般者是多對多的關係。
該模型可簡化表示為下圖:
本系統基於RBAC許可權模型,採用shiro框架進行許可權控制。只有角色為超級管理員的使用者才能進行系統的許可權管理,許可權級別細化到選單選項。
注:
匯入專案到STS
感謝一位韓國道友給我發的郵件,介紹了將production_ssm匯入到STS中,並將詳細過程與注意事項完整記錄了下來。非常感謝他的文件,也為STS的使用提供了參考。
參見:匯入production_ssm到STS
檔案上傳配置
在本地建立上傳圖片和檔案的資料夾,如我的存放路徑是在D:\upload\temp\img,D:\upload\temp\file資料夾下,然後修改tomcat的配置檔案server.xml,新增虛擬路徑,將對圖片和檔案的請求url對映到本機硬碟的相應路徑,如下:
<Host name="localhost" appBase="webapps"
unpackWARs="true" autoDeploy="true">
<!-- SingleSignOn valve, share authentication between web applications
Documentation at: /docs/config/valve.html -->
<!--
<Valve className="org.apache.catalina.authenticator.SingleSignOn" />
-->
<!-- Access log processes all example.
Documentation at: /docs/config/valve.html
Note: The pattern used is equivalent to using pattern="common" -->
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
prefix="localhost_access_log" suffix=".txt"
pattern="%h %l %u %t "%r" %s %b" />
<!-- 在Host標籤下新增下面兩行,配置虛擬路徑到你本機的資料夾 -->
<Context path="/pic" docBase="D:\upload\temp\img" crossContext="true" trusted="true" reloadable="true"/>
<Context path="/file" docBase="D:\upload\temp\file" crossContext="true" trusted="true" reloadable="true"/>
</Host>
idea classpath配置
idea引入專案後,resources目錄在eclipse中是在classpath下的,而在idea中變成在classpath外,導致專案無法識別配置檔案。解決辦法是把resources資料夾加入到classpath中,請參照此博文操作:eclipse與idea中classpath配置路徑不同導致遷移專案時的FileNotFoundException問題
Mybatis逆向工程
系統使用了Mybatis的逆向工程,依據資料庫表自動生成domain和mapper(注:自動生成的程式碼都是針對單表,若需多表整合,則要手動修改實現),其中,針對每個資料庫表,都會生成兩個封裝物件,可以認為example物件是對其相應的ORM對映物件查詢條件的封裝。逆向工程的實現–Mybatis Generator的程式碼託管在https://github.com/mybatis/generator,程式碼down下來後,配置generatorConfig.xml檔案,如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
"http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
<context id="testTables" targetRuntime="MyBatis3">
<commentGenerator>
<!-- 是否去除自動生成的註釋 true:是 : false:否 -->
<property name="suppressAllComments" value="true" />
</commentGenerator>
<!--資料庫連線的資訊:驅動類、連線地址、使用者名稱、密碼 -->
<jdbcConnection driverClass="com.mysql.jdbc.Driver"
connectionURL="jdbc:mysql://localhost:3306/production_ms" userId="root"
password="root">
</jdbcConnection>
<!-- 預設false,把JDBC DECIMAL 和 NUMERIC 型別解析為 Integer,為 true時把JDBC DECIMAL 和
NUMERIC 型別解析為java.math.BigDecimal -->
<javaTypeResolver>
<property name="forceBigDecimals" value="false" />
</javaTypeResolver>
<!-- targetProject:生成PO類的位置 -->
<javaModelGenerator targetPackage="org.hqu.production_ms.domain"
targetProject=".\src">
<!-- enableSubPackages:是否讓schema作為包的字尾 -->
<property name="enableSubPackages" value="false" />
<!-- 從資料庫返回的值被清理前後的空格 -->
<property name="trimStrings" value="true" />
</javaModelGenerator>
<!-- targetProject:mapper對映檔案生成的位置 -->
<sqlMapGenerator targetPackage="org.hqu.production_ms.mapper"
targetProject=".\src">
<!-- enableSubPackages:是否讓schema作為包的字尾 -->
<property name="enableSubPackages" value="false" />
</sqlMapGenerator>
<!-- targetPackage:mapper介面生成的位置 -->
<javaClientGenerator type="XMLMAPPER"
targetPackage="org.hqu.production_ms.mapper"
targetProject=".\src">
<!-- enableSubPackages:是否讓schema作為包的字尾 -->
<property name="enableSubPackages" value="false" />
</javaClientGenerator>
<!-- 指定資料庫表 -->
<table schema="" tableName="unqualify_apply"></table>
</context>
</generatorConfiguration>
修改完成後,執行main方法即可。需要注意的是,若要重新生成,則需把已經生成的檔案刪除,因為它不會自己覆蓋,導致檔案混亂。