1. 程式人生 > >Java Web實戰08-Spring、Spring MVC和Hibernate實現收銀機系統(XML版本)

Java Web實戰08-Spring、Spring MVC和Hibernate實現收銀機系統(XML版本)

前面參加一個公司的活動,做了一份收銀機系統的作業,當時時間緊,花費一天時間用Swing介面做的,比較簡單。程式碼在GitHub:https://github.com/yefengzhichen/twTask。最近正好學習了Spring,以及瞭解了Html和JSP,於是就將此作業改寫成了Spring、Spring MVC、Hibernate、Html和JSP結合的版本。


一、需求簡介

  商店的收銀機系統,會根據購買商品和商店的打折活動進行打折。已知商品資訊包含:名稱,數量單位,單價,類別和條形碼(偽)。以下是單個商品物件的結構:

barcode: 'ITEM000000', name: '可口可樂', unit: '
', category: '食品', subCategory: '碳酸飲料', price: 3.00

實現功能

1、輸入商品條形碼列表,輸出小票詳細資訊的功能。

輸入例子:Item0002,Item0010-10。逗號分隔商品,“-”分隔條形碼和數量或者重量。

輸出為:

` *<沒錢賺商店>購物清單* 名稱:apple,數量:10.0kg,單價:13.00(元),小計:130.00(元),優惠:10.00(元)  名稱:milk,數量:1.0box,單價:3.50(元),小計:3.50(元)  單品滿100減10塊商品: 商品:apple,原價:130.0(元),優惠:10.0(元) 
總計:123.50(元) 節省:10.00(元) 

2、增加打折商品的功能,輸入需要打折的商品條形碼。

除外,為了練習Hibernate相關,增加了以下功能:

3、註冊功能,輸入註冊資訊儲存到資料庫。

4、登入功能,驗證使用者是否有效,有效則進入收銀機系統。

5、動態新增商品資訊功能

主介面展示如下:


二、實現詳細過程

  開發環境搭建以及Maven工程構建和本系列之前的一樣,在此略過。

2.1 JAR包引入

  整個專案中,使用的JAR基本都是最新的,直接到Maven Repository上搜索複製的。主要用到的是:Spring 4和Hibernate 5。詳細JAR見下面的pom.xml內容:

<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.yefeng.spring</groupId>
	<artifactId>cashapp</artifactId>
	<packaging>war</packaging>
	<version>0.0.1-SNAPSHOT</version>
	<name>cashapp Maven Webapp</name>
	<url>http://maven.apache.org</url>
	<dependencies>
		<dependency>
			<groupId>junit</groupId>
			<artifactId>junit</artifactId>
			<version>4.12</version>
			<scope>test</scope>
		</dependency>
		<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>javax.servlet-api</artifactId>
			<version>3.1.0</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>4.3.0.RELEASE</version>
		</dependency>
		<!-- https://mvnrepository.com/artifact/org.springframework/spring-core -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-core</artifactId>
			<version>4.3.0.RELEASE</version>
		</dependency>
		<!-- https://mvnrepository.com/artifact/org.springframework/spring-beans -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-beans</artifactId>
			<version>4.3.0.RELEASE</version>
		</dependency>
		<!-- https://mvnrepository.com/artifact/org.springframework/spring-expression -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-expression</artifactId>
			<version>4.3.0.RELEASE</version>
		</dependency>
		<!-- https://mvnrepository.com/artifact/org.springframework/spring-aop -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-aop</artifactId>
			<version>4.3.0.RELEASE</version>
		</dependency>
		<!-- https://mvnrepository.com/artifact/org.springframework/spring-web -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-web</artifactId>
			<version>4.3.0.RELEASE</version>
		</dependency>
		<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webmvc</artifactId>
			<version>4.3.0.RELEASE</version>
		</dependency>

		<!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-core -->
		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-core</artifactId>
			<version>5.2.1.Final</version>
		</dependency>
		<!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-annotations 
			<dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-annotations</artifactId> 
			<version>3.5.6-Final</version> </dependency> -->
		<!-- https://mvnrepository.com/artifact/c3p0/c3p0 -->
		<dependency>
			<groupId>c3p0</groupId>
			<artifactId>c3p0</artifactId>
			<version>0.9.1.2</version>
		</dependency>
		<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>6.0.3</version>
		</dependency>
		<!-- https://mvnrepository.com/artifact/org.springframework/spring-orm -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-orm</artifactId>
			<version>4.3.1.RELEASE</version>
		</dependency>
		<!-- https://mvnrepository.com/artifact/org.jboss.spec.javax.transaction/jboss-transaction-api_1.1_spec -->
		<dependency>
			<groupId>org.jboss.spec.javax.transaction</groupId>
			<artifactId>jboss-transaction-api_1.1_spec</artifactId>
			<version>1.0.1.Final</version>
		</dependency>
		<!-- https://mvnrepository.com/artifact/org.springframework/spring-tx -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-tx</artifactId>
			<version>4.3.1.RELEASE</version>
		</dependency>
		<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
		<dependency>
			<groupId>org.aspectj</groupId>
			<artifactId>aspectjweaver</artifactId>
			<version>1.8.9</version>
		</dependency>
		<!-- https://mvnrepository.com/artifact/jstl/jstl -->
		<dependency>
			<groupId>jstl</groupId>
			<artifactId>jstl</artifactId>
			<version>1.2</version>
		</dependency>
		<!-- https://mvnrepository.com/artifact/org.springframework/spring-test -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-test</artifactId>
			<version>4.3.0.RELEASE</version>
		</dependency>
		<!-- https://mvnrepository.com/artifact/commons-lang/commons-lang -->
		<dependency>
			<groupId>commons-lang</groupId>
			<artifactId>commons-lang</artifactId>
			<version>2.6</version>
		</dependency>
		<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api -->
		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-api</artifactId>
			<version>1.7.21</version>
		</dependency>
		<!-- https://mvnrepository.com/artifact/org.hibernate.common/hibernate-commons-annotations -->
		<dependency>
			<groupId>org.hibernate.common</groupId>
			<artifactId>hibernate-commons-annotations</artifactId>
			<version>5.0.1.Final</version>
		</dependency>
	</dependencies>
	<build>
		<finalName>cashapp</finalName>
	</build>
</project>

2.2配置web.xml和各種元件bean

  因為將bean配置到兩個xml檔案root-context.xml、cashapp-context.xml中,web.xml中配置很簡單,配置分發器和監聽器,以及兩個檔案的路徑以及對映即可。其中,<param-value>的路徑預設從根路徑webapp下查詢,因此當配置在類路徑下時,需要加classpath字首。兩個context檔案位置放到webapp下或者類路徑下都是可以的。 web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://java.sun.com/xml/ns/javaee"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
	id="schedule-console" version="3.0">
	<display-name>Archetype Created Web Application</display-name>

	<!-- 根配置檔案路徑,配置除web元件以外的bean,後端的資料層和中間層-->
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>classpath:root-context.xml</param-value>
	</context-param>
	<!--載入上面的根配置檔案監聽器  -->
	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>
	<!-- 配置分發器,載入web元件的bean,如控制器、檢視解析器 -->
	<servlet>
		<servlet-name>cashapp</servlet-name>
		<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
		<init-param>
			<param-name>contextConfigLocation</param-name>
			<param-value>/WEB-INF/config/cashapp-context.xml</param-value>
		</init-param>
		<load-on-startup>1</load-on-startup>
	</servlet>
	<!-- 處理器對映 -->
	<servlet-mapping>
		<servlet-name>cashapp</servlet-name>
		<url-pattern>/</url-pattern>
	</servlet-mapping>

</web-app>
  cashapp-context.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:context="http://www.springframework.org/schema/context"
	xmlns:mvc="http://www.springframework.org/schema/mvc"
	xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
		http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">
	<!-- 靜態資源路徑配置,配置後,靜態資源將不用分發器處理即可獲得,此專案中未使用 -->
	<mvc:resources mapping="/static/**" location="/WEB-INF/static/" />  
	<!-- mvc配置註解驅動 -->
	<mvc:annotation-driven/>
	<!-- 啟動自動掃面元件 -->
	<context:component-scan base-package="com.yefeng.cashapp.web"/>
	<!-- 檢視處理器,自動新增字首字尾 -->
	<bean id="viewResolver"
		class="org.springframework.web.servlet.view.InternalResourceViewResolver">
		<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
		<property name="prefix" value="/WEB-INF/views/" />
		<property name="suffix" value=".jsp" />
	</bean>
</beans>

  root-context.xml,配置了資料庫屬性,以及C3P0資料來源,HIbernate事務管理器,並定義了相應的事務屬性。雖然此書的資料庫操作都很簡單,並沒有多個表一起修改的操作,但為了後面擴充套件,因此定義事務。
<?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:aop="http://www.springframework.org/schema/aop"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:tx="http://www.springframework.org/schema/tx"
	xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
		http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.3.xsd">
	<!-- 啟動切面自動代理 -->
	<aop:aspectj-autoproxy proxy-target-class="true" />  
	<!-- 讀取資料來源配置 -->
	<context:property-placeholder location="classpath:mysql.properties" />
	<!-- 自動掃面DAO和Service層的元件 -->
	<context:component-scan base-package="com.yefeng.cashapp.dao"></context:component-scan>
	<context:component-scan base-package="com.yefeng.cashapp.service"></context:component-scan>
	<!-- 資料來源bean, -->
	<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
		<property name="user" value="${user}"></property>
		<property name="password" value="${password}"></property>
		<property name="driverClass" value="${driverClass}"></property>
		<property name="jdbcUrl" value="${jdbcUrl}"></property>
		<property name="initialPoolSize" value="${initPoolSize}"></property>
		<property name="maxPoolSize" value="${maxPoolSize}"></property>
	</bean>
	<!--配置Hibernate sessionFactory-->
	<bean id="sessionFactory"
		class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
		<property name="dataSource" ref="dataSource"></property>
		<property name="configLocation" value="classpath:hibernate.cfg.xml"></property>
		<property name="mappingLocations">
			<list>
				<value>classpath:com/yefeng/cashapp/model/User.hbm.xml</value>
				<value>classpath:com/yefeng/cashapp/model/Product.hbm.xml</value>
			</list>
		</property>
	</bean>
	<!--配置Hibernate事務管理器 -->
	<bean id="transactionManager"
		class="org.springframework.orm.hibernate5.HibernateTransactionManager">
		<property name="sessionFactory" ref="sessionFactory"></property>
	</bean>
	<!--配置事務切面屬性 -->
	<tx:advice id="txAdvice" transaction-manager="transactionManager">
		<tx:attributes>
			<tx:method name="get*" read-only="true" />
			<tx:method name="*" />
		</tx:attributes>
	</tx:advice>
	<!--配置切點 -->
	<aop:config>
		<aop:pointcut id="daoPointcut"
			expression="execution(* com.yefeng.cashapp.dao.*.*(..))" />
		<aop:advisor advice-ref="txAdvice" pointcut-ref="daoPointcut" />
	</aop:config>
</beans>

資料庫連線檔案mysql.properties內容:
user=root
password=
#com.mysql.cj.jdbc.Driver 
driverClass=com.mysql.jdbc.Driver
jdbcUrl=jdbc:mysql://localhost:3306/cashapp?serverTimezone=UTC
  
initPoolSize=5
maxPoolSize=10

HIbernate配置檔案,和之前的配置一樣:
<?xml version="1.0" encoding="UTF-8"?>  
<!DOCTYPE hibernate-configuration PUBLIC  
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"  
        "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">  
<hibernate-configuration>  
    <session-factory>  
        <property name="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect  
        </property>  
        <property name="hibernate.show_sql">true</property>  
        <property name="hibernate.format_sql">true</property>  
        <property name="hibernate.temp.use_jdbc_metadata_defaults">false</property>  
        <property name="hibernate.hbm2ddl.auto">update</property>  
    </session-factory>  
</hibernate-configuration>  

到此,所有的配置已經完成,裡面涉及的bean將在下面說明。

2.3 Model層

  定義一個User類,對應資料庫中user表,儲存使用者名稱、密碼以及描述資訊:
package com.yefeng.cashapp.model;

public class User {
	private String name;
	private String password;
	private String description;
	
	public User() {
		super();
	}	
	
	public User(String name, String password, String description) {
		super();
		this.name = name;
		this.password = password;
		this.description = description;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public String getDescription() {
		return description;
	}

	public void setDescription(String description) {
		this.description = description;
	}


 
   
  商品資訊Product類:
  
 
  
package com.yefeng.cashapp.model;

/**
 * @author yefengzhichen
 * 2016年7月10日
 */
public class Product {
    // 名稱,數量單位,單價,類別和條形碼(偽)
    private String barcode;
    private String name;
    private String unit;
    private String category;
    private String subCategory;
    private Double price;
    private boolean isDiscount;

    public Product() {
    }

    public Product(String barcode, String name, String unit, String category, String subCategory, Double price) {
        this.barcode = barcode;
        this.name = name;
        this.unit = unit;
        this.category = category;
        this.subCategory = subCategory;
        this.price = price;
    }
    
    public Product(String barcode, String name, String unit, String category, String subCategory, Double price,
			boolean isDiscount) {
		super();
		this.barcode = barcode;
		this.name = name;
		this.unit = unit;
		this.category = category;
		this.subCategory = subCategory;
		this.price = price;
		this.isDiscount = isDiscount;
	}

	public String getBarcode() {
        return barcode;
    }

    public void setBarcode(String barcode) {
        this.barcode = barcode;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getUnit() {
        return unit;
    }

    public void setUnit(String unit) {
        this.unit = unit;
    }

    public String getCategory() {
        return category;
    }

    public void setCategory(String category) {
        this.category = category;
    }

    public String getSubCategory() {
        return subCategory;
    }

    public void setSubCategory(String subCategory) {
        this.subCategory = subCategory;
    }

    public Double getPrice() {
        return price;
    }

    public void setPrice(Double price) {
        this.price = price;
    }

	public boolean isDiscount() {
		return isDiscount;
	}

	public void setDiscount(boolean isDiscount) {
		this.isDiscount = isDiscount;
	}

	@Override
	public String toString() {
		return "Product [barcode=" + barcode + ", name=" + name + ", unit=" + unit + ", category=" + category
				+ ", subCategory=" + subCategory + ", price=" + price + "]";
	}
    
}

利用IDE自動生成相應的Hibernate對映檔案:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 2016-7-10 20:28:23 by Hibernate Tools 3.4.0.CR1 -->
<hibernate-mapping>
    <class name="com.yefeng.cashapp.model.User" table="USER">
        <id name="name" type="java.lang.String">
            <column name="NAME" />
            <generator class="assigned" />
        </id>
        <property name="password" type="java.lang.String">
            <column name="PASSWORD" />
        </property>
        <property name="description" type="java.lang.String">
            <column name="DESCRIPTION" />
        </property>
    </class>
</hibernate-mapping>

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 2016-7-12 20:25:34 by Hibernate Tools 3.4.0.CR1 -->
<hibernate-mapping>
    <class name="com.yefeng.cashapp.model.Product" table="PRODUCT">
        <id name="barcode" type="java.lang.String">
            <column name="BARCODE" />
            <generator class="assigned" />
        </id>
        <property name="name" type="java.lang.String">
            <column name="NAME" />
        </property>
        <property name="unit" type="java.lang.String">
            <column name="UNIT" />
        </property>
        <property name="category" type="java.lang.String">
            <column name="CATEGORY" />
        </property>
        <property name="subCategory" type="java.lang.String">
            <column name="SUBCATEGORY" />
        </property>
        <property name="price" type="java.lang.Double">
            <column name="PRICE" />
        </property>
        <property name="isDiscount" type="boolean" access="field">
            <column name="ISDISCOUNT" />
        </property>
    </class>
</hibernate-mapping>

2.4 DAO層

對以上的兩個model類,分別實現對應的DAO層,推薦使用介面程式設計,因此先定義介面UserDao:
package com.yefeng.cashapp.dao;

import com.yefeng.cashapp.model.User;

public interface UserDao {
	public void save(User user);
	public boolean isValid(User user);
	public void updatePassword(User user);
	public User get(String name);
}

ProductDao:
package com.yefeng.cashapp.dao;

import java.util.List;
import com.yefeng.cashapp.model.Product;

public interface ProductDao {
	public void save(Product product);
	public void update(Product product);
	public Product getByBarcode(String barcode);
	public boolean contains(Product product);
	public List<Product> getAll();
	public void setDiscount(String barcode);
}

對應的實現UserDaoImpl:
package com.yefeng.cashapp.dao;

import java.util.List;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.query.Query;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import com.yefeng.cashapp.model.User;

@Repository(value="userDao")
public class UserDaoImpl implements UserDao {
	@Autowired
	private SessionFactory sessionFactory;

	public Session getSession() {
		return sessionFactory.getCurrentSession();
	}
	
	@Override
	public void save(User user) {
		getSession().save(user);
	}
	
	@Override
	public boolean isValid(User user) {
		String name = user.getName();
		String hql = "select password from User where name = ?";
		List<String> result = getSession().createQuery(hql).setParameter(0, name).getResultList();
		String realPassword = result.get(0);
		if (user.getPassword().equals(realPassword)) {
			return true;
		}
		return false;
	}

	@Override
	public void updatePassword(User user) {
		String name = user.getName();
		String password = user.getPassword();
//		String hql = "update User u set u.password = ? where u.name = ?";
//		getSession().createQuery(hql).setParameter(0, password).setParameter(1, name);
//		推薦下面的命名引數方式
		String hql2 = "update User u set u.password=:password where u.name=:name";
		Query query2 = getSession().createQuery(hql2);
		query2.setParameter("password", password);
		query2.setParameter("name", name);
		query2.executeUpdate();
	}

	@Override
	public User get(String name) {
		String hql = "select u from User u where name = ?";
		List<User> result = getSession().createQuery(hql).setParameter(0, name).getResultList();
		return result.get(0);
	}
}

對應的ProductDaoImpl:
package com.yefeng.cashapp.dao;

import java.util.List;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.query.Query;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import com.yefeng.cashapp.model.Product;

@Repository(value = "productDao")
public class ProductDaoImpl implements ProductDao {

	@Autowired
	private SessionFactory sessionFactory;

	public Session getSession() {
		return sessionFactory.getCurrentSession();
	}

	@Override
	public void save(Product product) {
		if (getSession().contains(product) == false) {
			getSession().save(product);
		}
	}

	@Override
	public void update(Product product) {
		String barcode = product.getBarcode();
		String hql = "delete from Product where barcode = ?";
		getSession().createQuery(hql).setParameter(0, barcode).executeUpdate();
		getSession().save(product);
	}

	@Override
	public Product getByBarcode(String barcode) {
		String hql = "select p from Product p where barcode = ?";
		List<Product> result = getSession().createQuery(hql).setParameter(0, barcode).getResultList();
		return result.get(0);
	}

	@Override
	public boolean contains(Product product) {
		String barcode = product.getBarcode();
		String hql = "select p from Product p where barcode = ?";
		List<Product> result = getSession().createQuery(hql).setParameter(0, barcode).getResultList();
		return result.size() > 0;
	}

	@Override
	public List<Product> getAll() {
		String hql = "select p from Product p";
		List<Product> result = getSession().createQuery(hql).getResultList();
		return result;
	}

	@Override
	public void setDiscount(String barcode) {
		String hql = "update Product p set p.isDiscount=true where p.barcode=:barcode";
		Query query = getSession().createQuery(hql);
		query.setParameter("barcode", barcode);
		query.executeUpdate();		
	}

}

2.5 Service層

Service層主要實現商品價格清單功能,需要使用DAO進行處理計算,介面ProcessService只有一個方法:
package com.yefeng.cashapp.service;

public interface ProcessService {
	public String calculateAll(String inputString);
}

ProcessServiceImpl:
package com.yefeng.cashapp.service;

import java.text.DecimalFormat;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import com.yefeng.cashapp.dao.ProductDao;
import com.yefeng.cashapp.model.Product;


/**
 * @author yefengzhichen
 * 2016年7月15日
 */
@Repository(value = "processService")
public class ProcessServiceImpl implements ProcessService {

	@Autowired
	private ProductDao productDao;

	public String calculateAll(String inputString){
		Map<String, Double> map = parseInput(inputString);
		return calculatePrice(map);
	}
	//解析條形碼輸入,輸入中包含數量,進行分割	
	public Map<String, Double> parseInput(String inputString) {
		String[] input = inputString.split(",");
		Map<String, Double> buy = new HashMap<>();
		for (String str : input) {
			String[] content = str.split("-");
			double num = 0.0;
			if (content.length == 1) {
				num = 1.0;
			} else if (content.length == 2) {
				num = Double.parseDouble(content[1]);
			}
			String key = content[0];
			if (buy.containsKey(key)) {
				num += buy.get(key);
				buy.put(key, num);
			} else {
				buy.put(key, num);
			}
		}
		return buy;
	}
	//計算總的價格、以及實現滿100減10的優惠,最後返回一個小票的字串
	public String calculatePrice(Map<String, Double> buy) {
		String result;
		List<Product> productList = productDao.getAll();
		String detail = "";

		StringBuffer detailPrice = new StringBuffer("` *<沒錢賺商店>購物清單*");
		StringBuffer discountPrice = new StringBuffer("");
		StringBuffer tatalPrice = new StringBuffer("");
		double totalSum = 0.0;
		double discountSum = 0.0;
		// 小數位數
		DecimalFormat df = new DecimalFormat("######0.00");
		for (Map.Entry<String, Double> entry : buy.entrySet()) {
			String barcode = entry.getKey();
			Product product = productDao.getByBarcode(barcode);
			double value = entry.getValue();

			double price = product.getPrice();
			String name = product.getName();
			String unit = product.getUnit();
			boolean isDiscount = product.isDiscount();
			// String sub = product.getSubCategory();
			detailPrice.append(" 名稱:" + name + ",數量:" + value + "" + unit + ",單價:" + df.format(price) + "(元)");
			double subTotal = value * price;
			if (isDiscount && subTotal >= 100.0) {
				double dis = (int) subTotal / 100 * 10;
				totalSum += subTotal;
				discountSum += dis;
				detailPrice.append(",小計:" + df.format(subTotal) + "(元),優惠:" + df.format(dis) + "(元) ");
				if (discountPrice.length() < 1) {
					discountPrice.append("單品滿100減10塊商品:");
				}
				discountPrice.append(" 商品:" + name + ",原價:" + subTotal + "(元),優惠:" + dis + "(元) ");
			} else {
				totalSum += subTotal;
				detailPrice.append(",小計:" + df.format(subTotal) + "(元) ");
			}
		}
		tatalPrice.append("總計:" + df.format(totalSum - discountSum) + "(元)");
		if (discountPrice.length() > 1) {
			tatalPrice.append(" 節省:" + df.format(discountSum) + "(元)");
		}
		result = detailPrice.toString() + "\n" + discountPrice.toString() + "\n" + tatalPrice.toString();
		return result;
	}

}

2.6 Controller層

首先是首頁控制器,直接返回home.jsp。
package com.yefeng.cashapp.web;

import static org.springframework.web.bind.annotation.RequestMethod.*;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping(value="/")
public class HomeController {
	
	@RequestMapping(method=GET)
	public String home(){
		return "home";
	}
}

Usercontroller,定義了使用者註冊、登入驗證相關的處理:
package com.yefeng.cashapp.web;

import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.yefeng.cashapp.dao.ProductDao;
import com.yefeng.cashapp.dao.UserDao;
import com.yefeng.cashapp.model.Product;
import com.yefeng.cashapp.model.User;

/**
 * @author yefengzhichen
 * 2016年7月15日
 */
@Controller
@RequestMapping(value = "/user")
public class UserController {
	@Autowired
	private UserDao userDao;
	@Autowired
	private ProductDao productDao;

	@RequestMapping(value = "/register", method = RequestMethod.GET)
	public String showRegisterForm() {
		return "registerForm";
	}

	@RequestMapping(value = "/register", method = RequestMethod.POST)
	public String processRegister(User user) {
		userDao.save(user);
		return "redirect:/user/" + user.getName();
	}

	@RequestMapping(value = "/login", method = RequestMethod.GET)
	public String showLogin(User user, Model model) {
		return "login";
	}
	
	@RequestMapping(value = "/login", method = RequestMethod.POST)
	public String processLogin(User user, Model model) {
		boolean valid = userDao.isValid(user);
		if (!valid) {
			return "redirect:/user/login";
		}
		/*List<Product> productList = productDao.getAll();
		model.addAttribute(productList);
		String discountList = "";
		for (int i = 0; i < productList.size(); ++i) {
			Product product = productList.get(i);
			if (product.isDiscount()) {
				discountList += product.getBarcode();
				if (i != productList.size()) {
					discountList += ", ";
				}
			}
		}
		String detail = "The input product barcode is null";
		model.addAttribute(discountList);
		model.addAttribute(detail);*/
		return "redirect:/start";
	}

	@RequestMapping(value = "/{name}", method = RequestMethod.GET)
	public String showBloggerProfile(@PathVariable String name, Model model) {
		User user = userDao.get(name);
		model.addAttribute(user);
		return "profile";
	}
}

ProcessController,處理需要裡面的增加商品資訊、增加打折商品、計算價格等處理:
package com.yefeng.cashapp.web;

import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.yefeng.cashapp.dao.ProductDao;
import com.yefeng.cashapp.dao.UserDao;
import com.yefeng.cashapp.model.Product;
import com.yefeng.cashapp.service.ProcessService;

/**
 * @author yefengzhichen
 * 2016年7月15日
 */
@Controller
@RequestMapping(value = "/start")
public class ProcessController {

	@Autowired
	private UserDao userDao;
	@Autowired
	private ProductDao productDao;
	@Autowired
	private ProcessService processService;

	@RequestMapping(method = RequestMethod.GET)
	public String shopApp(Model model) {
		addModelAttribute(model);
		String detail = "The input product barcode is null";
		model.addAttribute("detail", detail);
		return "start";
	}

	// Item0010,apple,kg,fruit,fresh fruit,13.00
	@RequestMapping(value = "/inputProduct", method = RequestMethod.POST)
	public String addProduct(String inputProduct, Model model) {
		String[] proStr = inputProduct.split(";");
		for (String pro : proStr) {
			String[] list = pro.split(",");
			String barcode = list[0];
			String name = list[1];
			String unit = list[2];
			String category = list[3];
			String subCategory = list[4];
			Double price = Double.parseDouble(list[5]);
			Product product = new Product(barcode, name, unit, category, subCategory, price);
			productDao.save(product);
		}
		addModelAttribute(model);
		return "start";
	}

	@RequestMapping(value = "/inputDiscount", method = RequestMethod.POST)
	public String addDiscount(String inputDiscount, Model model) {
		String[] barcodes = inputDiscount.split(",");
		for (String barcode : barcodes) {
			productDao.setDiscount(barcode);
		}
		addModelAttribute(model);
		return "start";
	}

	@RequestMapping(value = "/inputBarcode", method = RequestMethod.POST)
	public String inputItem(String inputBarcode, Model model) {
		String detail = processService.calculateAll(inputBarcode);
		model.addAttribute("datail", detail);
		addModelAttribute(model);
		return "start";
	}

	public void addModelAttribute(Model model) {
		List<Product> productList = productDao.getAll();
		model.addAttribute("productList", productList);
		String discountList = "";
		for (int i = 0; i < productList.size(); ++i) {
			Product product = productList.get(i);
			if (product.isDiscount()) {
				if (discountList.length() == 0) {
					discountList += product.getBarcode();
				} else {
					discountList += (", " + product.getBarcode());
				}
			}
		}
		model.addAttribute("discountList", discountList);
	}

}

2.7 View層

在介紹之前,先瀏覽一下目錄結構如下:

home.jsp,簡單的定義兩個連結,分別是註冊和登入:
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
	pageEncoding="ISO-8859-1"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ page session="false"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Blog for people who follows your heart</title>
</head>
<body>
	<h1 align="center">Welcome to cashapp</h1>
	<div align="center">
	<a style="font-size:16px;" href="<c:url value="/user/login" />">Login</a>  
	<a style="font-size:16px;" href="<c:url value="/user/register" />">Register</a>
	</div>
</body>
</html>

RegisterForm,定義註冊介面:
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
	pageEncoding="ISO-8859-1"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ page session="false"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>cashapp</title>
</head>
<body>
	<h1 align="center">Register</h1>
	<div align="center">
	<form action="/cashapp/user/register" method="post">   
	<!-- real :action="/cashapp/user/register" -->
		UserName: <input type="text" name="name" /> <br/>
		PassWord: <input type="password" name="password" /> <br/>
		Description: <input type="text" name="description" /> <br/>
		<input type="submit" value="Register">
	</form>
	</div>>
</body>
</html>

profile.jsp,顯示註冊成功的介面,顯示名稱和介紹:
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
	pageEncoding="ISO-8859-1"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ page session="false"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>Blog for people who follows your heart</title>
</head>
<body>
	<h4 align="center">Welcome to cashapp</h4>
	<div align="center">
	Your name: <c:out value="${user.name}"></c:out> <br>
	Your description: <c:out value="${user.description}"></c:out>
	</div>
</body>
</html>

start.jsp,收銀機系統的主介面,大多數功能處理在此處:
<%@ page language="java" contentType="text/html; charset=UTF-8"
	pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ page session="false"%>

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>cashapp</title>
</head>
<body>
	<h1 align="center">A brief web cashapp</h1>

	<p style="FONT-SIZE: 16px" align="center">
		Product information list: <br>
	</p>
	<!-- 商品資訊表格輸出 -->
	<table align="center" border="2">
		<tr>
				<td width="100">barcode</td>
				<td width="100">name</td>
				<td width="100">unit</td>
				<td width="100">category</td>
				<td width="140">subCategory</td>
				<td width="100">price</td>
		</tr>
		<c:forEach items="${productList}" var="product">
			<tr>
				<td width="100"><c:out value="${product.barcode}" /></td>
				<td width="100"><c:out value="${product.name}" /></td>
				<td width="100"><c:out value="${product.unit}" /></td>
				<td width="100"><c:out value="${product.category}" /></td>
				<td width="140"><c:out value="${product.subCategory}" /></td>
				<td width="100"><c:out value="${product.price}" /></td>
			</tr>
		</c:forEach>
	</table>
		<!-- 輸入購買的商品條形碼 -->
	<div align="center">
		<br> Input product barcode list(Example:Item0002,Item0010-10): <br>
	<form action="/cashapp/start/inputBarcode" method="post" id="inputBarcode">		
		<textarea name="inputBarcode" cols="100" rows="1"></textarea> <br>
			<input type="submit" value="InputBarcode">
		</form>
	</div>
	<!-- 輸出商品價格詳細清單 -->
	<div align="center">
		<br> Output product price details: <br>
		<textarea rows="6" cols="100"><c:out value="${datail}"></c:out> </textarea>	
	</div>	
	<!-- 輸入要增加商品資訊/cashapp/start/inputProduct  Item0010,apple,kg,fruit,fresh fruit,13.00-->
	<div align="center">
		<br> Input product information list(Example:Item0010,apple,kg,fruit,fresh fruit,13.00): <br>		
		<form action="/cashapp/start/inputProduct" method="post" id="inputProduct">		
		<textarea name="inputProduct" cols="100" rows="2"></textarea> <br>
			<input type="submit" value="inputProduct">
		</form>
	</div>	
	<!-- 已經儲存的打折商品條形碼列表 -->
	<div align="center">
		<br> Discount information list: <br>
		<textarea rows="2" cols="100"><c:out
				value="${discountList}"></c:out> </textarea>
	</div>
	<!-- 輸入要增加的打折商品條形碼-->
	<div align="center">
		<br> Input discount product list(Example:Item0002,Item0010): <br>		
		<form action="/cashapp/start/inputDiscount" method="post" id="inputDiscount">		
		<textarea name="inputDiscount" cols="100" rows="1"></textarea> <br>
			<input type="submit" value="InputDiscount">
		</form>
	</div>
	
</body>
</html>