常學(xué)偉
(陽煤豐喜肥業(yè)(集團(tuán))有限責(zé)任公司聞喜復(fù)肥分公司,山西運(yùn)城 044402)
陽煤豐喜肥業(yè)(集團(tuán))有限責(zé)任公司聞喜復(fù)肥分公司擁有兩條15萬噸高塔復(fù)合肥生產(chǎn)線、一條15萬噸轉(zhuǎn)鼓造粒生產(chǎn)線,一條5萬噸的轉(zhuǎn)鼓造粒生產(chǎn)線,另設(shè)有液體肥、水溶肥新型品種肥料生產(chǎn)線,年生產(chǎn)能力達(dá)到50萬噸,是華北地區(qū)最大的復(fù)合肥生產(chǎn)企業(yè)之一,產(chǎn)品適用于全國不同地域、各種作物的用肥需求。產(chǎn)品年產(chǎn)量大、品類多及倉儲區(qū)域大等實際情況給公司的倉儲管理帶來一定難度。
目前,我公司信息化管理方面,在采購、銷售、倉儲及財務(wù)等環(huán)節(jié)均采用浪潮公司ERP軟件,大大減輕了各部門的工作量,并實現(xiàn)與上級集團(tuán)公司業(yè)務(wù)的無縫對接。但在實際應(yīng)用中發(fā)現(xiàn),ERP系統(tǒng)對倉儲現(xiàn)場的貨位管理不完善,且ERP是桌面軟件已投入使用多年,不具備移動端在線查詢功能,另貨物出入庫頻繁,產(chǎn)品型號多,造成保管找不到貨的情況時有發(fā)生,針對這種情況,本文主要采用Java Web框架的primefaces開源類庫和hibernate框架開發(fā)一個方便在線查詢貨位、庫存數(shù)等記錄,以此來簡化倉儲現(xiàn)場貨位管理,提高工作效率。
圖1 復(fù)合肥倉儲貨位前臺查詢界面Fig.1 The front desk query interface of compound fertilizer storage space
本倉儲貨位管理系統(tǒng)通過“Primefaces+Hibernate”java 框架編程技術(shù),結(jié)合Mysql數(shù)據(jù)庫實現(xiàn)。程序運(yùn)行在阿里云服務(wù)器,服務(wù)器軟件為Tcomat,服務(wù)器版本為7.2,數(shù)據(jù)庫為Mysql,數(shù)據(jù)庫版本為5.0。該系統(tǒng)分為前臺查詢,后臺管理及數(shù)據(jù)庫三部分組成。
前臺界面為倉儲管理人員提供一個能夠查詢產(chǎn)品貨位的功能,方便通過移動端設(shè)備隨時查詢,主要功能為登錄界面、當(dāng)前庫存明細(xì)、按配方匯總明細(xì)等三個功能。如圖1所示。
后臺管理由管理員操作,功能為期初庫存、當(dāng)期產(chǎn)品入庫、當(dāng)期產(chǎn)品出庫、當(dāng)前庫存、結(jié)賬及用戶管理等功能。如圖2所示。
底層數(shù)據(jù)庫采用Mysql來存儲數(shù)據(jù),分別設(shè)計:期初庫存表openingStockTable,入庫表storageVolumeTable和出庫表deliveryVolumnTable、用戶表user_manager四個表格。這四個數(shù)據(jù)表結(jié)構(gòu)如表1-表4。
圖2 復(fù)合肥倉儲貨位后臺管理界面Fig.2 The back-end management interface of compound fertilizer storage space
表1 期初庫存表OpeningStockTableTab.1 OpeningStockTable
表2 入庫表StorageVolumeTableTab.2 StorageVolumeTable storageVolumeTable
登錄窗口設(shè)置用戶名輸入框、密碼輸入框、信息提示、登錄按鈕等primefaces組件。單擊登錄按鈕后,出現(xiàn)如下幾種情況:
(1)當(dāng)用戶名或秘密為空時,信息提示“內(nèi)容為空,請重新輸入”。
(2) 當(dāng)輸入用戶名在user_manager數(shù)據(jù)表中不存在,信息提示“用戶不存在,請重新輸入”。
(3)當(dāng)輸入的用戶名存在,但輸入的密碼與數(shù)據(jù)表中密碼不一致,信息提示“密碼錯誤,請重新輸入”。
(4)當(dāng)輸入用戶名和密碼均正確,但用戶名所對應(yīng)的用戶類型不符合登錄類型時,信息提示“輸入用戶沒有登錄權(quán)限,請聯(lián)系管理員!”。用戶類型設(shè)置“前臺用戶”和“管理員”兩種,“前臺用戶”只允許登錄前臺查詢界面,“管理員”只允許登錄后臺管理界面。
(5)當(dāng)輸入用戶名、密碼、用戶類型和數(shù)據(jù)表信息相符時,從登錄界面跳轉(zhuǎn)值前臺主頁面或者后臺管理頁面。
(1)單筆出入庫記錄明細(xì)錄入,項目分別是:配方類別、配方名稱、倉庫名稱、貨位號、包裝袋樣式和型號、數(shù)量、貨物狀況等項目手動收入,記錄人、記錄時間由系統(tǒng)自動錄入。
(2)期初產(chǎn)品信息錄入,需判斷入庫產(chǎn)品在是否已經(jīng)存在,如果存在提示“期初庫存已存在記錄要輸入的記錄,無需再進(jìn)行輸入操作!”,如果不存在,則直接插入記錄即可。
(3)當(dāng)期產(chǎn)品入庫時,應(yīng)先判斷期初產(chǎn)品庫存中是否有相同記錄(數(shù)量信息除外),如果沒有,先在期初表中插入信息,然后再到當(dāng)期入庫表中插入。
(4)期初表中的當(dāng)期入庫總數(shù)、當(dāng)期出庫總數(shù)和當(dāng)前庫存數(shù)根據(jù)當(dāng)期入庫表和當(dāng)期出表中數(shù)據(jù)結(jié)合Hibernate HQL查詢中的sum函數(shù)和查詢條件,在插入或出庫完成并在頁面導(dǎo)向成功后更新。
(5)產(chǎn)品出庫時,應(yīng)當(dāng)判斷期初表中的當(dāng)前庫存總數(shù)和要出庫數(shù)大小,如果當(dāng)前庫存總數(shù)≥要出庫數(shù),則在出庫表中插入記錄,頁面導(dǎo)向成功并自動更新期初表中出庫總數(shù)和當(dāng)前庫存數(shù)等。如果要出庫的產(chǎn)品不存在,則提示信息“產(chǎn)品不存在”,如果出庫數(shù)大于當(dāng)前庫存數(shù),則提示信息“要出庫數(shù),超庫存數(shù)”。
(1)分別將期初表、入庫表、出庫表中的數(shù)據(jù)明細(xì)以表格形式顯示在頁面上。
(2)當(dāng)前庫存明細(xì)以表格形式顯示在頁面上。
(3)當(dāng)前庫存按照配方分類匯總,以條形圖表的形式顯示在頁面上。
(1)把期初庫存表openingStockTable中的當(dāng)前庫存數(shù)currentStock字段賦值給期初庫存openingStock字段;
(2)將期初庫存表openingStockTable中的當(dāng)期入庫總數(shù)storageVolumeSum、當(dāng)期出庫總數(shù)deliveryVolumeSum、當(dāng)前庫存數(shù)currentStock等三個字段數(shù)值清0;
(3)入庫表storageVolumeTable和出庫表storageVolume Table中的數(shù)據(jù)清0。
(1)java軟件開發(fā)包版本為:JDK7;
(2)開發(fā)軟件為NetBeans IDE 7.2軟件;
表3 出庫表StorageVolumeTableTab.3 Outbound table StorageVolumeTable
表4 用戶表user_managerTab.4 User table user_manager
(3)數(shù)據(jù)庫使用Mysql5.0;
(4)主要jar包。
1)Primefaces jar包:primefaces3.4.2.jar;
2)JSF jar包:jsf-api.jar、jsf-impl.jar、standard.jar、jstl.jar;
3)Hibernate jar包:hibernate3.jar;
4)MySQL JDBC 驅(qū)動程序:mysql-connector-java-5.0.4-bin.jar.
因創(chuàng)建多個數(shù)據(jù)表,操作方法類似,所以下面以創(chuàng)建期初表為例,進(jìn)行闡述。
(1)根據(jù)1.3數(shù)據(jù)庫表的設(shè)計,創(chuàng)建持久化 JavaBean類文件,名稱為openingStockTable,并根據(jù)字段名及類型聲明相應(yīng)的屬性,最后設(shè)置get和set方法,實例如下:
public class openingStockTable {
public openingStockTable() {
}
private Long id; //編號
private String formulaStyle; //配方類別 尿基、硝基、轉(zhuǎn)鼓等
private String formulaName; //配方名稱
......
......
......
public Long getId() {
return id; }
public void setId(Long id) {
this.id = id; }
public String getFormulaStyle() {
return formulaStyle; }
public void setFormulaStyle(String formulaStyle) {
this.formulaStyle = formulaStyle; }
public String getFormulaName() {
return formulaName; }
public void setFormulaName(String formulaName) {
this.formulaName = formulaName;}
......
......
......
//因篇幅有限,上述省略號省略剩余
屬性的set和get方法創(chuàng)建。
}
(2)映射配置文件創(chuàng)建。
通過NetBeansIDE開發(fā)工具創(chuàng)建映射配置文件,文件名稱為openingStockTable.hbm.xml,映射配置文件中將上述Bean文件中的屬性與要創(chuàng)建的數(shù)據(jù)表中的字段建立起映射關(guān)系。文件位置放置在WEB-INF/class文件夾下,映射內(nèi)容如下:
"openingStockTable"> ...... ...... ......
說明:⑴通過class、id和property標(biāo)簽將4.2.1中的JavaBean類與數(shù)據(jù)庫表,類屬性與數(shù)據(jù)庫表字段建立起映射關(guān)系。⑵上述表中,如果類屬性為float類型的,則property標(biāo)簽中的type值應(yīng)為“float”;類屬性為Date日期類型的,則property標(biāo)簽中的type值應(yīng)為“date”;類屬性為String類型的,則property標(biāo)簽中的type值應(yīng)為“string”。
(3)連接數(shù)據(jù)庫。
通過NetBeansIDE開發(fā)工具創(chuàng)建hibernate.cfg.xml文件,文件位置放置在WEB-INF/class文件夾下,內(nèi)容如下:
mysql://localhost:3306/xyfilems?useUnicode=true&characterEncoding=UTF-8
說明:通過property標(biāo)簽建立數(shù)據(jù)庫連接,并將前面創(chuàng)建的四個數(shù)據(jù)庫表的映射文件進(jìn)行配置。
(4)創(chuàng)建數(shù)據(jù)庫,并通過java程序自動創(chuàng)建數(shù)據(jù)表。
使用Hibernate框架,可以讓我們以面向?qū)ο蟮乃枷氩僮鲾?shù)據(jù)庫,無需直接操作數(shù)據(jù)。通過Hibernate框架提供的SchemaExport類,可以在創(chuàng)建好數(shù)據(jù)庫后直接根據(jù)上述持久化類、映射文件配置信息直接創(chuàng)建表格。創(chuàng)建一個名稱為createDataBaseTable的java主類文件,內(nèi)容如下:
import org.hibernate.cfg.Configuration;
import org.hibernate.tool.hbm2ddl.SchemaExport;
public class createDataBaseTable {
public static void main(String[]args) {
// TODO code application logic here
try {
Configuration cfg = new Configuration().configure();
SchemaExport exporg = new SchemaExport(cfg);
exporg.create(true, true);
} catch (Exception ex) {
} finally {
}}}
說明:運(yùn)行上述文件后,前面配置的4個數(shù)據(jù)庫表自動創(chuàng)建成功。
對于在項目業(yè)務(wù)邏輯層需要與數(shù)據(jù)庫建立連接、終止的部分,這里通過建立一個工具類,方便在后續(xù)在項目中調(diào)用,內(nèi)如如下:
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class HibernateUtil {
private static final SessionFactory sessionFactory;
static {
try {
Configuration config = new Configuration().configure();
sessionFactory = config.buildSessionFactory();
} catch (Throwable ex) {
// Log the exception.
System.err.println("Initial SessionFactory creation failed." + ex);
throw new ExceptionInInitializerError(ex);
}
}
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
public static Session getSession() {
return sessionFactory.openSession();
}
public static void closeSession(Session session) {
if (session != null) {
if (session.isOpen()) {
session.close();
}
}
}
}
使用NetBeansIDE開發(fā)工具創(chuàng)建項目后,在WEB-INF文件夾下會自動創(chuàng)建wen.xml配置文件,配置內(nèi)容如下:
30
說明:該配置文件指定了primefaces的核心控制器javax.faces.webapp.FacesServlet和項目的默認(rèn)主頁訪問路徑等信息。
使用NetBeansIDE開發(fā)工具創(chuàng)建faces-config.xml文件,創(chuàng)建后初始文件如下:
xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/webfacesconfig_2_1.xsd">
該配置文件用于注冊Primefaces 受管Bean文件,通過“managed-bean”標(biāo)簽實現(xiàn)注冊,另外,Primefaces組件頁面之間的導(dǎo)向配置,通過“navigation-rule”標(biāo)簽實現(xiàn)。
Web層的頁面設(shè)計通過Primefaces提供的組件完成,因篇幅有限,這里主要將項目中應(yīng)用較多的組件介紹,其他組件的使用可以參考primefaces參考手冊了解。
3.6.1 組件實現(xiàn)聯(lián)動功能
在項目開發(fā)中,有時需要通過選擇一個下拉列表項,另外一個下拉列表自動顯示子選項,這功能可以通過下拉列表組件的rendered屬性、p:ajax組件和valueChange Listener事件來實現(xiàn)。功能實現(xiàn)方法如下:
(1)創(chuàng)建Bean文件,并在faces-config.xml文件中注冊。
1)faces-config.xml文件中注冊Bean
2)Bean文件代碼,下述省略部分為聲明的屬性設(shè)置set和get方法。
package warehouseSystem.productInfoInput;
import java.util.HashMap;
import javax.faces.event.ValueChangeEvent;
import org.primefaces.component.outputlabel.OutputLabel;
import org.primefaces.component.selectonemenu.SelectOneMenu;
public class openingStock_insert {
public openingStock_insert() {
formulaStyleMap.put("尿基", "尿基");
formulaStyleMap.put("硝基", "硝基");
niaojiformulaMap.put("28-6-6", "28-6-6");
niaojiformulaMap.put("24-14-7", "24-14-7");
niaojiformulaMap.put("25-10-5", "25-10-5");
niaojiformulaMap.put("27-14-10", "27-14-10");
xiaojiformulaMap.put("硝15-15-15","硝15-15-15");
xiaojiformulaMap.put("硝15-7-21","硝15-7-21");
xiaojiformulaMap.put("硝16-6-21","硝16-6-21");
}
//配方類型
public String formulaStyleValue;
public String getFormulaStyleValue() {......}
public void setFormulaStyleValue(String formulaStyleValue) {......}
HashMap formulaStyleMap = new HashMap();
public HashMap getFormulaStyleMap() {......}
public void setFormulaStyleMap(HashMap formulaStyleMap) {......}
//配方選項賦值
HashMap niaojiformulaMap = new HashMap();
public HashMap getNiaojiformulaMap(){......}
public void setNiaojiformulaMap(HashMap niaojiformulaMap) {......}
//配方選項賦值
HashMap xiaojiformulaMap = new HashMap();
public HashMap getXiaojiformulaMap() {......}
public void setXiaojiformulaMap(HashMap xiaojiformulaMap) {......}
OutputLabel oplFormulaName = new OutputLabel();
public OutputLabel getOplFormulaName(){......}
public void setOplFormulaName(OutputLabel oplFormulaName) {......}
SelectOneMenu somNiaoji = new SelectOneMenu();
public SelectOneMenu getSomNiaoji() {......}
public void setSomNiaoji(SelectOneMenu somNiaoji){......}
SelectOneMenu somxiaoji = new SelectOneMenu();
public SelectOneMenu getSomxiaoji() {......}
public void setSomxiaoji(SelectOneMenu somxiaoji){......}
//當(dāng)觸發(fā)ValueChange事件時,會根據(jù)選項值執(zhí)行相應(yīng)的動作。
public void changeFormulaNameEvent(ValueChange Event e) {
//獲取下拉選項的值
Object countryName = e.getNewValue();
//this.setCities(this.getChinaMapCity());
if (countryName.equals("尿基")) {
oplFormulaName.setRendered(true);
somNiaoji.setRendered(true);
somxiaoji.setRendered(false);
} else if (countryName.equals("硝基")) {
oplFormulaName.setRendered(true);
somNiaoji.setRendered(false);
somxiaoji.setRendered(true);
}
}
}
(2)使用NetBeansIDE開發(fā)工具創(chuàng)建xhtml網(wǎng)頁文件,代碼如下:
xmlns:h="http://java.sun.com/jsf/html"
xmlns:p="http://primefaces.org/ui"
xmlns:c="http://java.sun.com/jsp/jstl/core"
xmlns:f="http://java.sun.com/jsf/core">
說明:上述功能為選擇id屬性為“formulaStyleId”的p:selectOneMenu組件的值,觸發(fā)valueChangeListener事件,p:ajax組件的ajax屬性刷新form范圍,另外兩個組件會根據(jù)選擇的值,判斷是否顯示和顯示子選項。
3.6.2 p:dataTable表格組件
(1)組件屬性(表5)。
(2)從數(shù)據(jù)庫中調(diào)用數(shù)據(jù),并見數(shù)據(jù)通過p:dataTable表格組件顯示出來,可以通過hibernate將數(shù)據(jù)復(fù)制給List對象,然后再將List對象值賦值給ListDataModel數(shù)據(jù)模型,最后在數(shù)據(jù)表格中即可顯示。
1)在受控Bean文件中,聲明ListDataModel數(shù)據(jù)模型。
public ListDataModel allWarehouseDataModel = new ListDataModel();
public ListDataModel getAllWarehouseDataModel() {
return allWarehouseDataModel;
}
public void setAllWarehouseDataModel(ListDataModel allWarehouseDataModel) {
this.allWarehouseDataModel = allWarehouseData Model;
}
2)在受控Bean文件中,通過hibernate調(diào)用數(shù)據(jù)庫數(shù)據(jù),并將數(shù)據(jù)賦值給ListDataModel對象。
Session session = null;
try {
session = HibernateUtil.getSession();
session.beginTransaction();
Query query = session.createQuery(" from openingStockTable order by formulaStyle");
List names = query.list();
allWarehouseDataModel.setWrappedData(names);
} catch (Exception ex) {
} finally {
HibernateUtil.closeSession(session);
}
3)在xhtml網(wǎng)頁文件中,通過p:dataTable表格組件顯示數(shù)據(jù)。
rows="8" paginatorPosition="bottom" paginator AlwaysVisible="false" emptyMessage="無內(nèi)容"paginatorTemplate="{CurrentPageReport} {FirstPage Link} {PreviousPageLink} {PageLinks} {NextPageLink}{LastPageLink}">
根據(jù)需要顯示的數(shù)據(jù),在p:dataTable組件中,增加p:column組件,即可增加數(shù)據(jù)表的列數(shù)。p:dataTable組件的value值綁定的就是前面已經(jīng)創(chuàng)建好的ListDataModel對象。
3.6.3 p:barChart條形圖表
PrimeFaces框架共提供了有100多個支持AJAX的JSF組件。其中,圖表組件就提供了餅圖、折線圖、條形圖、圈圖、氣泡圖等多個圖表組件供開發(fā)者直接使用,功能豐富,大大提高了開發(fā)效率。這里介紹項目中使用的條形圖表的應(yīng)用。
要將數(shù)據(jù)在p:barChart條形圖表組件中顯示,需要調(diào)用primefaces類庫中的CartesianChartModel圖表模型和ChartSeries類對象。首先,通過hibernate從數(shù)據(jù)庫中調(diào)取數(shù)據(jù),并將數(shù)據(jù)賦值給Object[]數(shù)組,然后再將對象數(shù)組值賦值給ChartSeries對象,最后再將ChartSeries對象值賦值給CartesianChartModel圖表模型。具體實現(xiàn)代碼如下:
(1)在受控Bean文件中,聲明CartesianChartModel數(shù)據(jù)模型和ChartSeries對象。
CartesianChartModel openingStockChartModelNiaoji= new CartesianChartModel();
public CartesianChartModel getOpeningStockChart ModelNiaoji() {
return openingStockChartModelNiaoji;
}
public void setOpeningStockChartModelNiaoji(CartesianChartModel openingStockChartModelNiaoji) {
this.openingStockChartModelNiaoji = openingStock ChartModelNiaoji;
}
ChartSeries openingStockCSNiaoji = new ChartSeries();
表5 p:dataTable組件屬性值Tab.5 p:dataTable component attribute values
public ChartSeries getOpeningStockCSNiaoji() {
return openingStockCSNiaoji;
}
public void setOpeningStockCSNiaoji(ChartSeries openingStockCSNiaoji) {
this.openingStockCSNiaoji = openingStockCSNiaoji;
}
(2)在受控Bean文件中的無參構(gòu)造函數(shù)中,通過hibernate調(diào)用數(shù)據(jù)庫數(shù)據(jù),并將數(shù)據(jù)賦值給ChartSeries對象,然后再將ChartSeries對象值賦值給CartesianChartModel數(shù)據(jù)模型。
Session session = null;
try {
session = HibernateUtil.getSession();
session.beginTransaction();
Query query = session.createQuery("select formulaName,sum(currentStock) from openingStockTable where formulaStyle= :fs group by formulaName");
query.setString("fs", "尿基");
List li = query.list();
Iterator ite = li.iterator();
while (ite.hasNext()) {
Object[]obj = (Object[]) ite.next();
openingStockCSNiaoji.set(obj[0],Float.valueOf(obj[1].toString()));
}
openingStockChartModelNiaoji.addSeries(opening StockCSNiaoji);
} catch (Exception ex) {
//session.getTransaction().rollback();
} finally {
HibernateUtil.closeSession(session);
}
(3)在xhtml網(wǎng)頁文件中,通過p:barChart組件將數(shù)據(jù)以條形圖的形式顯示出來。
p:barChart組件條形圖表組件的value值為前面創(chuàng)建的CartesianChartModel對象。
本文主要介紹了采用“Primefaces+Hibernate”框架實現(xiàn)企業(yè)倉儲管理貨位管理項目的技術(shù)實現(xiàn)。通過Prime faces提供的豐富組件和采用Hibernate面向?qū)ο蟮臄?shù)據(jù)操作,使得項目開發(fā)效率大大提高。