此程序編碼風格相當不嚴謹,僅僅是完成功能,不建議模仿!
前期調研
當當網
例如打開當當網,在購物商城頁面可以看到不同類別的商品鏈接。
通過點擊這些鏈接,將切換到不同的頁面展示不同類別的商品,例如我打開圖書頁面查看圖書的商品信息。
在搜索框中搜索商品,當當網會返回查詢的結果集,並且顯示在網頁上。例如我搜索圖書《Java 核心技術》,當當網回顯了相關商品的商品信息。
把商品放入購物車之后,我們可以對購物車內的商品進行操作,例如增加商品數量、減少商品數量、刪除商品、清空購物車和結算。
任務分配
組員 | 任務分配 |
---|---|
林智凱 | 登錄系統后端(MySQL + Socket)、購物車類、user 類 |
吳海波 | 登錄系統前端、購物車系統 GUI 界面、整合代碼 |
韓一佳 | MySQL 數據庫設計並連接、商品類設計 |
李存浩 | 商品類及其子類實現 |
登錄系統
登錄系統將基於三層架構進行設計,使用 Socket 和 MySQL 進行實現,同時使用一定的信息加密提高安全性。詳情見Java 程序設計——登錄系統。
登錄之后將自動進入購物車菜單界面,菜單界面的 GUI 設計如圖。
站內短信系統
二層架構
站內短信系統使用的是二層架構,也就是客戶端直接向存儲層請求數據,存儲層更新或檢索數據之后進行響應。此處使用 MySQL 數據庫作為數據的存儲層,這就需要客戶端實現對數據庫的遠程連接。
程序的包結構
商品的類設計
Commodity 類
Commodity 類具有任何商品共有的一些屬性,並且提供了屬性訪問器和修改器。
package logic.product;
/**
* 這是一個關於購物車商品的超類
* @author 李存浩、韓一佳
*
*/
public class Commodity { //商品超類
//private String explain;//商品說明
private Double price;//商品價格
private Integer stock;//商品庫存
private Integer number;//商品編號
private String name;//商品名稱
private static int temp=0;
private String date;//入庫時間
{
temp++;
this.number =temp;
}
/**
*
*/
public Commodity() { //無參構造方法
}
/*
* public Commodity(Double price,Integer stock,String explain,Integer
* number,String date) { this.price=price; this.explain=explain;
* this.stock=stock; this.number=number; this.date=date; }
*/
/**
*
* @param price 商品的價格屬性
* @param stock 商品的庫存屬性
* @param date 商品的入庫時間
*/
public Commodity(Double price, Integer stock, String date) { //有參構造函數
this.price = price;
this.stock = stock;
this.date = date;
}
/**
*
* @return 返回值為Double類型,返回值為商品價格.
*/
public Double getPrice() { //返回商品價格
return price;
}
/**
* 這是一個設置商品價格的有參構造方法
* @param price 設置商品的價格,類型為Double
*/
public void setPrice(Double price) { //設置商品價格
this.price = price;
}
/**
*
* @return 返回值類型為Integer,返回值為商品的庫存情況
*/
public Integer getStock() { //返回商品庫存
return stock;
}
/**
* 這是一個設置商品的初始庫存的有參構造方法
* @param stock 設置商品的初始庫存
*/
public void setStock(Integer stock) {//設置商品庫存
this.stock = stock;
}
/**
*
* @return 返回值為Integer類型,返回值為商品編號.
*/
public Integer getNumber() {//返回商品編號
return number;
}
/**
* 這是一個設置商品編號的有參構造方法
* @param number 設置商品的編號
*/
public void setNumber(Integer number) {//設置商品編號
this.number = number;
}
/**
*
* @return 返回值為String類型,返回值為商品名稱.
*/
public String getName() {
return name;
}
/**
* 這是一個設置商品名稱的有參構造方法
* @param name 設置商品的名稱
*/
public void setName(String name) {
this.name=name;
}
/*
* public String getExplain() { return explain; }
*
* public void setExplain(String explain) { this.explain = explain; }
*/
/**
*
* @return 返回值為String類型,返回值為商品的入庫時間.
*/
public String getDate() { //返回商品日期
return date;
}
/**
* 這是一個設置商品入庫時間的有參構造方法
* @param 設置商品的入庫時間
*/
public void setDate(String date) {//設置商品日期
this.date = date;
}
public String toString() { //將其他類型轉化為字符串類型返回
return "Commodity [name="+name+",price=" + price + ", stock=" + stock + ", number=" + number + ", date=" + date + "]";
}
}
Book 類
Book 類繼承了 Commodity 類,一個 Book 對象除了要具備商品共有的屬性,還需要關注書的作者和出版社等只有書籍商品才具有的屬性。
package logic.product;
/**
* 這是有關書籍類商品類的有關的類,為Commodity的子類
* @author 李存浩、韓一佳
*
*/
public class Book extends Commodity {//繼承父類:Commodity
private String author;// 作者
private String press;//出版社
/**
* {@inheritDoc} 直接繼承父類的屬性:price stock date name
* @param author 設置書本的作者名稱
* @param press 設置書本的出版社
* @param price 設置書本的價格
* @param stock 設置書本的初始庫存
* @param date 設置書本的入庫日期
* @param name 設置書本的名稱
*/
public Book(String author,String press,Double price,Integer stock,String date,String name) { //有參構造方法
this.author=author;
this.press=press;
super.setPrice(price);//繼承父類設置的價格屬性
super.setStock(stock);//繼承父類設置的商品的庫存屬性
super.setDate(date);//繼承父類設置的商品日期
super.setName(name);//繼承父類設置的商品名稱
}
/**
*
* @return 返回作者的名稱
*/
public String getAuthor() { //設置返回作者的getter方法
return author;
}
/**
* 這是一個設置書本作者名稱的有參構造方法
* @param author設置書本作者的名稱,類型為String
*/
public void setAuthor(String author) {//設置作者的setter方法
this.author = author;
}
/**
*
* @return 返回書本的出版社
*/
public String getPress() {//設置返回出版社的getter方法
return press;
}
/**
* 這是一個設置書本出版社稱的有參構造方法
* @param 設置書本的出版社,類型為String
*/
public void setPress(String press) {//設置出版社的setter方法
this.press = press;
}
/**
*
*/
@Override
public boolean equals(Object obj) {//調用父類的equals方法,返回值為true時,繼續比較
if(this==obj)
return true;
if(obj==null) //obj為空值時,返回false
return false;
else {
if(obj instanceof Book) {
Book c=(Book) obj;
if(c.getNumber().equals(this.getNumber())) {//用equals方法比較兩者的編號相同時,返回值為true
return true;
}
}
}
return false;//其余返回false
}
/**
* 用toString方法返回值
*/
@Override
public String toString() {//將其他類型轉化為字符串類型並返回
return "Book [name="+super.getName()+",author=" + author + ", press=" + press + ", price=" + super.getPrice() + ", stock="+ super.getStock() + ", number=" + super.getNumber() + "]";
}
}
Eproduct 類
Eproduct 類繼承了 Commodity 類,一個 Eproduct 對象除了要具備商品共有的屬性,還需要關注電器的品牌和型號等只有電器才具有的屬性。
package logic.product;
/**
* 這是有關電子產品類商品類的有關的類,為Commodity的子類
* @author 李存浩、韓一佳
*
*/
public class Eproduct extends Commodity{ //電子產品類繼承父類Commodity
private String brand;//品牌
private String model_number;//型號
/**
* 這是一個有參構造方法,設定關於Eproduct類的相關屬性,且繼承了父類的相關屬性
* {@inheritDoc} 繼承父類的屬性有:price stock date
* @param brand 設置電子產品的品牌
* @param price 設置電子產品的價格
* @param stock 設置電子產品的初始庫存
* @param explain 填充電子產品的相關說明
* @param date 設置電子產品的入庫日期
* @param name 設置電子產品的名稱
*/
public Eproduct(String brand,Double price,Integer stock,String explain,String date,String name) {//設置有參構造方法
this.brand=brand;
super.setPrice(price);//繼承父類的價格屬性
super.setStock(stock);//繼承父類的庫存屬性
super.setDate(date);//繼承父類的入庫日期屬性
super.setName(name);
}
/**
*
* @return 返回電子產品的品牌名稱
*/
public String getBrand() {//設置返回品牌的getter方法
return brand;
}
/**
* 這是一個設置電子產品品牌的有參構造方法
* @param brand 設置電子產品的品牌名
*/
public void setBrand(String brand) {//設置品牌的setter方法
this.brand = brand;
}
/**
*
* @return 返回電子產品的型號
*/
public String getModel_number() {//設置返回商品型號的getter方法
return model_number;
}
/**
* 這是一個設置電子產品型號的有參構造方法
* @param model_number 置電子產品的型號
*/
public void setModel_number(String model_number) {//設置電子商品型號的setter方法
this.model_number = model_number;
}
@Override
public boolean equals(Object obj) {
if (this == obj)//通過equals比較,若返回值為真時,繼續比較
return true;
if (obj == null)//obj為空時,返回false;
return false;
else {
if (obj instanceof Eproduct) {
Eproduct c = (Eproduct) obj;
if (c.getNumber().equals(this.getNumber())) {//c與obj 用equals方法比較,若c的數量與obj的編號相等時,返回為true
return true;
}
}
}
return false;//其余返回false
}
@Override
public String toString() {//以toString()方法將其他類型轉化為字符串類型返回
return "Eproduct [name="+super.getName()+",brand=" + brand + ",price=" + super.getPrice() + ", stock=" + super.getStock() + ", number="+ super.getNumber() + ", date=" + super.getDate() + "]";
}
}
Fruits 類
Fruits 類繼承了 Commodity 類,一個 Fruits 對象除了要具備商品共有的屬性,還需要關注水果的保質期和產地等只有水果才具有的屬性。
package logic.product;
/**
* 這是有關水果類商品類的有關的類,為 Commodity 的子類
* @author 李存浩、韓一佳
*
*/
public class Fruits extends Commodity{//繼承父類:Commodity
private Integer period;//記錄保質期
private String origin; //產地
public Fruits() { //無參構造方法
}
/**
* {@inheritDoc} 直接繼承父類的屬性:price stock date name
* @param date 設置水果的入庫日期
* @param period 設置水果的保質期
* @param origin 設置水果的生產地
* @param price 設置水果的價格
* @param stock 設置水果的初始庫存
* @param name 設置水果的名稱
*/
public Fruits(String date, Integer period, String origin, Double price, Integer stock,String name) { //有參構造方法
this.origin = origin; //水果產地
this.period = period; //水果保質期
super.setPrice(price);//設置繼承父類的商品價格
super.setStock(stock);//設置繼承父類的商品庫存
super.setDate(date);//設置繼承父類的商品日期
super.setName(name);
}
/**
*
* @return 返回水果的保質期
*/
public Integer getPeriod() {//設置返回保證期的getter方法
return period;
}
/**
* 這是一個設置水果保質期的有參構造方法
* @param period 設置水果的保質期
*/
public void setPeriod(Integer period) {//設置設置保證期的setter 方法
this.period = period;
}
/**
*
* @return 返回水果的生產地
*/
public String getOrigin() {//設置返回水果的產地的getter方法
return origin;
}
/**
*這是一個設置水果生產地的有參構造方法
* @param origin 設置水果的生產地
*/
public void setOrigin(String origin) {//設置水果的產地的setter方法
this.origin = origin;
}
public boolean equals(Object obj) {
if (this == obj) //通過equals比較,若返回值為真時,繼續比較
return true;
if (obj == null) //obj為空時,返回false;
return false;
else {
if (obj instanceof Fruits) { //c與obj 用equals方法比較,若c的數量與obj的編號相等時,返回為true
Fruits c = (Fruits) obj;
if (c.getNumber().equals(this.getNumber())) {
return true;
}
}
}
return false;//其余情況返回false
}
@Override
public String toString() {//以toString()方法將其他類型轉化為字符串類型返回
return "Fruits [name="+super.getName()+",date=" + super.getDate() + ", period=" + period + ", price=" + super.getPrice() + ", stock="+ super.getStock() + ", number=" + super.getNumber() + ", origin=" + origin + "]";
}
}
購物車的類設計
購物車的狀態應當與用戶綁定在一起,換言之每個用戶都應該有專屬的購物車。因此設計思路為每個實例化的用戶對象綁定一個購物車類作為其屬性,在購物車類中存儲商品類對象。
shoppingCar 類
shoppingCar 類基於 HashMap 實現購物車,HashMap 容器以 Commodity 為鍵,Integer 為值,也就是對某種商品和其數量構成映射。shoppingCar 類實現了加商品、減商品、計算總價和清空的功能。
import java.util.*;
import logic.product.*;
/**
* 購物車類,基於HashMap實現,支持增加和刪除商品,計算總價格
* @author 林智凱
* @version 1.0
*/
public class shoppingCar {
private HashMap<Commodity,Integer> shopping_car;
/**
* 這個方法是shoppingCar對象的構造器
*/
public shoppingCar() {
shopping_car = new HashMap<Commodity,Integer>();
}
public HashMap<Commodity,Integer> getShopping_car() {
return shopping_car;
}
/**
* 這個方法將向shoppingCar加入num個a_commodity商品
* @param a_commodity 被增加的商品,Commodity
* @param num 商品加入購物車的數量
*/
public void addCommodity(Commodity a_commodity,int num) {
shopping_car.merge(a_commodity, num, Integer::sum);
}
/**
* 這個方法將向shoppingCar移出num個a_commodity商品
* @param a_commodity 被移出的商品,Commodity
= */
public void reduceCommodity(Commodity a_commodity) {
shopping_car.remove(a_commodity);
}
/**
* 這個方法將計算購物車中的所有商品的總價
* @return 商品的總價,double
*/
public double calculateTotalPrice(){
double sum = 0;
for (Commodity key : shopping_car.keySet()) {
sum = sum + shopping_car.get(key) * key.getPrice();
}
return sum;
}
/**
* 清空購物車,也就是清除所有HashMap映射
*/
public void clearShoppingCar() {
shopping_car.clear();
}
}
Customer 類
同登錄系統那篇博客所說,當用戶登錄成功后,應該把該用戶信息實例化一個 Customer 來存儲。同時一位用戶應該對於一輛購物車,因此實例化 Customer 對象時,應當給用戶初始化購物車屬性。
import logic.car.*;
/**
* 這個類存儲了用戶名及其MD5加密,並且將調用UserBehavior類中的方法,實例化后綁定一台購物車給該用戶
* @author 林智凱
* @version 1.1
*/
public class Customer {
private final String username;
private final String username_md5;
private shoppingCar shopping_car;
/**
* 這個方法是customer對象的構造器
* @param username 用戶名,String
* @return customer對象
*/
public Customer(String username) {
this.username = username;
this.username_md5 = MD5Util.getMD5Str(username);
this.shopping_car = new shoppingCar();
}
/**
* 訪問字段username,用戶名
* @return username 用戶名
*/
public String getUsername() {
return username;
}
/**
* 訪問字段username_md,加密后的用戶名
* @return username_md 加密后的用戶名
*/
public String getUsername_md5() {
return username_md5;
}
/**
* 訪問字段shopping_car 綁定給用戶的購物車
* @return shopping_car 綁定給用戶的購物車
*/
public shoppingCar getShopping_car() {
return shopping_car;
}
}
GUI 設計
打開購物車界面,窗體展示了已經加入購物車中的商品和數量。
點擊刪除商品,可以將指定商品從購物車中移除。
點擊清空購物車,會把所有商品從購物車中移除。
數據庫連接並操作
ComDao 接口
由於商品的形式可以是多種數據庫或文件,因此定義 ComDao 接口指定了獲取商品信息的各種行為。購物車系統中與存儲結構交互的行為有 3 種,分別是精確查找、獲得結果集和修改庫存。
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Vector;
public interface ComDao {
public void connDB() throws Exception;//建立連接
public void closeDB() throws SQLException;//關閉連接
public Vector Find(String find, String table) throws Exception;//精確查找
public ResultSet GetRs(String table) throws Exception;//獲得結果集
public void ChangeStock(String table,int ns,int id) throws Exception;//修改庫存
}
ComMysql 類
ComMysql 類實現了 ComDao 接口,該類與 MySQL 數據庫進行交互,負責從數據庫中獲取並更新商品信息。
MySQL 數據庫設計
books 表
books 表用於存儲書籍類商品信息,表具有的字段如圖所示。
例如向 books 表中插入 3 個書籍信息。
eproducts 表
eproducts 表用於存儲電器類商品信息,表具有的字段如圖所示。
例如向 eproducts 表中插入 3 個電子產品信息。
fruits 表
fruits 表用於存儲水果類商品信息,表具有的字段如圖所示。
例如向 eproducts 表中插入 3 個水果商品信息。
GUI 界面設計
在商城菜單下,選擇“書籍”表單時,程序會自動向數據庫拉取書籍商品信息。
選擇“電子產品”表單時,程序會自動向數據庫拉取電器商品信息。
選擇“水果”表單時,程序會自動向數據庫拉取水果商品信息。
在搜索欄中輸入要檢索的商品信息,在“搜索結果”表單中回顯搜索到的商品信息。
如果搜索了不存在的商品,則輸出提示信息。