简易版网上书店
数据库准备,开发软件
用到的软件有:①MySQL数据库(5.7版本)②Navicat premium12③JDK1.8④Tomcat8.5⑤Jrebel(不是必须)⑥eclipse
首先,数据库设计。
我这里是用到了五个表:书本类别表,书本表,用户表,订单表和订单项表。
而且,主要的表都在最后添加了两个字段。
gmt_create TIMESTAMP null default current_timestamp,
gmt_modified TIMESTAMP null default current_timestamp on update current_timestamp
加不加的不影响程序运行,前者是表创建时间,后者是修改表的时间。是必备的表中三字段(id,gmt_create,gmt_modified),不需要自己加数据,创建的时候加上就行。
然后就是代码长篇预警
1、前台
创建一个web项目,点击next,不要直接点击finsh。然后最后一步会跳出这样的窗口,记得选中再finsh.
1.1首页
首页实现之后的样子
主界面的最新上架是根据上架时间来降序的,热销也是根据销量来的。
主界面数据加载用的过滤器,访问主界面的时候可以把数据存到request里面,然后用c标签遍历就好了。下图中用到了fmt标签(改变数字格式),引入jtsl和standard的jar包就可以用了,pattern是格式。
这里顺便提一下,我项目快写完的时候才发现,一个过滤器可以过滤多个界面。代码如下:
<filter>
<description>订单数据加载,一个过滤器映射两个界面</description>
<filter-name>OrderFilter</filter-name>
<filter-class>com.zking.book.utils.OrderFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>OrderFilter</filter-name>
<url-pattern>/customer/MyOrder1.jsp</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
</filter-mapping>
<filter-mapping>
<filter-name>OrderFilter</filter-name>
<url-pattern>/customer/MyOrder2.jsp</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
</filter-mapping>
1.2用户注册/登录
注册,登陆都是用的表单提交。自己写界面也可以,很简单的界面。获取数据,传入后台action,判断之后返回前台就好了。
这里我用的是config.xml的配置文件。下图是一个请求的流程。
而且,很重要的一点是:增删改都是重定向,查询是转发
在哪里改呢?
在config.xml中,forward标签中的redirect属性。false就是转发,反之。(这些东西都是在mvc jar包里有判断的)
// An highlighted block
<action path="/bookCateoryAction" type="com.zking.book.action.BookCateoryAction">
<forward name="listBook" path="/admin/listBook.jsp" redirect="false" />
<forward name="addBook" path="/admin/addBook.jsp" redirect="true" />
</action>
下面介绍了config.xml文件的标签以及属性作用。(难点)
上图中说到输入地址要通过config.xml找到对应的action,就是根据action标签的path和type属性来的。
比如:前台访问:/bookCateoryAction.action,那么会找到配置文件中action中的path有无/bookCateoryAction(后缀名在jar包中已经去掉),像上面代码中就能找到。所以就会访问对应路径(type)
“com.zking.book.action.BookCateoryAction“的文件。
那怎么跳出来呢?
在action(相当于之前写的servlet)方法中return “listBook”;然后就会到配置文件中来找forward标签中的name,如上代码找到了就会跳转(path)到"/admin/listBook.jsp";
其他方法跳转也是如此。
1.3书籍查询
1.3.1根据类别查询
首页中说了信息是怎样存取的。根据类别查询,不过我写了类别表和书籍表的连表查询这样好调用属性。
sql语句如下:
查询所有数据:“select b.*,bc.book_category_name from t_book b,t_book_category bc where b.book_category_id=bc.book_category_id”
根据类别查询:sql+=" and b.book_category_id="+“要查询的内容”;
不过我还加了判断书本是否已经上架,就是" and book_state=2"。
注意:这里sql语句查询的比较杂,多。一定要注意 sql+= 的时候一定要在 " and"前面打上空格,不然就会报错,数据库会把and和前面一个词连在一起。
当我点击首页右边的类别的时候,就会跳去findBook.jsp界面,把搜索到的东西用集合装着同首页一样用标签遍历。
注意:数据一定要用request.setAttribute(" ", )存着,用config.xml中的转发。如果使用重定向,分页可能会出问题。
效果如下:
1.3.2全文索引(单字符可用)
之前听说单字符查询要安装插件ngram。但是上网查找资料之后发现,MySQL5.7之后自带这个插件了,所以加语法就是了。
前台和类别查询是一样的,调用方法之后,跳到同一个界面(findBook.jsp)。只是注意两个存东西的request名要一样,比如:我类别查询之后request.setAttribute("listBook ",book );那么要使用索引查也一样存"listBook"名就行了。
如果索引和类别查询不是一个界面那就没有要求了。
数据库这边要改的东西:
① 安装MySQL的路径下有一个my.ini文件,右击编辑加入
"
ft_min_word_len = 1
ngram_token_size=1
"
以上两行代码,加在最后就行。这个可以让查询文字包含单个字符。
② 添加索引
ALTER TABLE t_book
ADD FULLTEXT INDEX fulltext_book (book_name,book_name_pinyin,book_author,publishing,book_desc
) WITH PARSER ngram;
以上代码:把全文索引fulltext_book加入表t_book中,括号中的列名都可以查询其中内容。
全文索引到底什么意思呢?
我自己的理解就是一次查询把几个列名中的东西都模糊查询一遍。比如:不用全文索引的时候,模糊查询书名中含"盗墓"的,那么所有含有"盗墓"的书都会找出来。用了之后,所有书名、作者、简介等等含有"盗墓"两个字的都会被查出来。
怎么用全文索引?
修改查询语句:
select b.*,bc.book_category_name from t_book b,t_book_category bc where b.book_category_id=bc.book_category_id and b.book_state=2 and MATCH (book_name,book_name_pinyin,book_author,publishing,book_desc) AGAINST (’"+要查询的内容+"’)
别看这么多就是加了一个条件而已。
1.4购物车
有两种做法,
一是session版本的,把东西存入session中可以使数据长时间存在。但是下一次登陆的时候就没有了。
二是数据库版本的。
表名 | 字段类型 |
---|---|
cid | BIGINT |
uid | BIGINT |
bid | BIGINT |
bookName | VARCHAR(20) |
bookCount | BIGINT |
bookPirce | DECIMAL(10,2) |
bookSum | DECIMAL(10,2) |
选择商品加入购物车的时候,要先判断之前的购物车是否含有了这个商品,含有的话就只要改变数量+1就行了。
还有一点要注意的,就是BigDecimal的加减乘除
不能直接 “+” “-” “*” “/” ,是有对应方法的,例如:
//加法
BigDecimal big1 = new BigDecimal("10");
BigDecimal big2 = new BigDecimal("5");
big1.add(big2);
方法名 | 对应方法 |
---|---|
加法 | add |
减法 | subtract |
乘法 | multiply |
除法 | divide |
如果要计算总价,在循环里面写上 sum=sum.add(big1);
1.5订单管理
1.5.1订单新增
前台把数据传入后台新增就好。
只不过单本点击结算的时候需要向后台传入书本ID,而新增界面没有书本ID,如果这样的话,那就要点击结算跳入后台拿到数据保存在作用域再来到新增界面。
我觉得很麻烦,因为这样就多了一步。所以,我选择了jsp界面跳转jsp界面。
这样的话,中间省去了跳转到action的一步。
实现步骤:
①在单本结算的界面,在点击立即结算的时候,跳转到新增订单界面。并且在后面带上参数。bid的值使用EL表达式写上。
<a href="addOrder.jsp?bookId=1">立即结算</a>
②在新增的界面,是表单提交的方法提交数据。在表单内设置隐藏域,用El表达式获取到url地址传过来的参数。El表达式会把url地址传过来的参数封装在param里面,用param点击出来就行。
<form>
<input type="hidden" name="bookId" value="${param.bookId}">
</form>
在订单新增的时候顺便把销量加1。
1.5.2订单查询
用户只能查到自己的订单,方法里面判断uid=当前用户uid,就行了。
为了及时刷新,这里同首页一样用了过滤器获取数据。这样的话,每次撤单或者签收之后,从后台过来又可以在过滤器中重新获取一遍。
1.5.3撤单
由于用的过滤器所以撤单和签收一样,点击之后跳到后台,修改购物车状态,在跳回来就行。
不用担心刷新的问题。
1.5.4签收
同上。跳转至不同方法就好了。
2、后台
2.1管理员登录(同界面判断权限)
这里管理员和普通用户在一个登陆界面登陆,action中会拿到user对象,然后判断权限type。返回不同的值,来达到跳转不同界面的效果。
为了防止其他除管理员以外的人登陆后台,这里设置了过滤器。
package com.zking.book.utils;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;