Java Web實戰08-Spring、Spring MVC和Hibernate實現收銀機系統(XML版本)
阿新 • • 發佈:2018-12-31
前面參加一個公司的活動,做了一份收銀機系統的作業,當時時間緊,花費一天時間用Swing介面做的,比較簡單。程式碼在GitHub:https://github.com/yefengzhichen/twTask。最近正好學習了Spring,以及瞭解了Html和JSP,於是就將此作業改寫成了Spring、Spring MVC、Hibernate、Html和JSP結合的版本。
一、需求簡介
商店的收銀機系統,會根據購買商品和商店的打折活動進行打折。已知商品資訊包含:名稱,數量單位,單價,類別和條形碼(偽)。以下是單個商品物件的結構:
barcode: 'ITEM000000', name: '可口可樂', unit: '實現功能:
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>