项目文档

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

1.原始需求:允许用户在互联网中购买分类书籍
2.需求分析:
* 用户管理
* 注册(发送邮件,第一次验证码,MD5加密)
* 激活
* 登录
* 分类管理
* 添加分类
* 查询分类
* 书籍管理
* 添加书籍(上传)-- manager
* 查询书籍(条件查询、分页)--client
* 购物车(存放session)
* 购买--下订单(在线支付)
* 权限管理(过滤器)
3.分析数据库的结构
* 用户表users(id,username,password, email,status, roles ,phone,address ) #rolse(admin,user,默认注册的用户为user)
* 分类表categorys(id categoryname,description)
* 书籍表books(id,title,price,author, quantity,imgUrl , description , categorys_id) # price单价
* 订单表orders(id,createdate, price ,users_id) # 总价
* 订单项ordersItem(id,orders_id,books_id, quantity,price) # 中间表(订单表与书籍表)* quantity购买的数量,price小计(books.price单价* ordersItem.quantity购买数量)
4.sql实现
# 1 创建数据库ebookstore
create database ebookstore character set utf8;
use ebookstore;
##### 表实现
# 1 用户表users(id,username,password, email,status, roles ,phone,address ) #rolse(admin,user,默认注册的用户为user)
create table users(
id varchar(32) primary key, #唯一标识,uuid值
username varchar(50) unique, # 唯一名称
password varchar(32), # MD5加密
email varchar(30), # 电子邮箱
status varchar(1), # 登录激活状态,0表示没有激活,1表示已经激活
roles varchar(10), # 用户的角色(权限时使用),admin管理员,user普通用户,默认注册的用户为user
phone varchar(30), # 手机
address varchar(255) # 地址
);
# 2 分类表categorys(id categoryname,description)
create table categorys(
id varchar(32) primary key,
categoryname varchar(50), # 分类名称
description varchar(500) # 描述
);
# 3 书籍表books(id,title,price,author, quantity,imgUrl , description , categorys_id) # price单价
create table books(
id varchar(32) primary key,
title varchar(60), # 标题
price double(6,2), # 单价,最大值为,9999.99
author varchar(50), # 作者
quantity int, # 数量,书籍的个数(库存)
imgUrl varchar(200), # 上传图片的位置(路径)
description varchar(500), # 描述
categorys_id varchar(32) # 分类表categorys(主表) 对应的外键,books(从表)
);
# 3.1 描述主外键
alter table books add constraint foreign key(categorys_id) references categorys(id);
# 4 订单表orders(id,createdate, price ,users_id) # 总价
create table orders(
id varchar(32) primary key,
createdate date, # 下订单的时间
price double(8,2), # 当前订单的总价,最大值999999.99
users_id varchar(32) # 用户表users(主表)对应的外键orders(从表)
);
# 4.1描述主外键
alter table orders add constraint foreign key(users_id) references users(id);
# 5 订单项ordersItem(id,orders_id,books_id, quantity,price)
# 中间表(订单表与书籍表)# quantity购买的数量,price小计(books.price单价# ordersItem.quantity购买数量)
create table ordersItem(
id varchar(32) primary key,
orders_id varchar(32), #订单表orders(主表)对应的外键,ordersItem从表
books_id varchar(32), # 书籍表books(主表)对应的外键,ordersItem从表
quantity int, # 购买的数量
price double(7,2) # 小计(books.price单价# ordersItem.quantity购买数量)
);
# 5.1 描述主外键,订单表orders(主表)对应的外键,ordersItem从表
alter table ordersItem add constraint foreign key(orders_id) references orders(id);
# 5.2 描述主外键,书籍表books(主表)对应的外键,ordersItem从表
alter table ordersItem add constraint foreign key(books_id) references books(id);
5.分析技术
* 使用的jar包
* mysql 驱动:mysql-connector-java-5.1.22-bin.jar
* c3p0连接池:
* c3p0-0.9.2-pre5.jar 核心包
* mchange-commons-java-0.2.3.jar 依赖包
* jdbc简化工具包DBUtils:commons-dbutils-1.4.jar
* JSP :显示页面,不需要提供jar,tomcat提供
* EL :在jsp替换jsp脚本的,显示数据,不需要提供jar
* JSTL :标签jsp替换jsp脚本的,主要逻辑判断if,循环foreach等,有两个,使用myeclipse
* javax.servlet.jsp.jstl.jar
* jstl-impl.jar
* 封装表单提交的数据到javabean,BeanUtils:
* commons-beanutils-1.8.3.jar
* commons-logging-1.1.1.jar
* 发送邮件:javamail
* mail.jar
* 文件上传:apache的fileupload
* commons-fileupload-1.2.2.jar
* commons-io-2.3.jar
* 配置文件
* c3p0-config.xml
* 工具类
* JdbcUtils
* StringUtils . getUUID(),getMD5V alue 获取随机id 和进行md5加密
* MailUtil 发送邮件的工具类
* 包结构
cn.itcast.ebookstore....
WebRoot/client 用户访问页面(前端程序)
WebRoot/manager 管理访问页面(后台管理程序)
-- main.jsp 程序入口(框架,不能使用<body>)
-- top.jsp 头部信息
-- left.jsp 左边的显示信息
-- ... 用于显示其他内容
6.分组管理(manager)
* 添加分组
* 查询所有分组
7.用户管理
* 用户的注册
* 登录|激活(自己完成)
开发javaweb项目,流程
* 不完全基于MVC
* 1.通关浏览器直接访问jsp(提供表单,获得浏览器端用户输入的数据)
* 如果jsp需要,其他查询得到的数据,必须通过servlet转发到jsp页面* 2.编写服务器端程序servlet,
* 获得提交的数据,封装
* 处理
* 选择视图--提示
* 3.处理时使用service
* 4.持久化数据dao
* 完全基于MVC
* 不能直接访问jsp,必须通过一个servlet,此servlet可以没有任何其他操作。

仅仅转发到jsp页面
* 其他与“不完全基于MVC”相同
* 带有条件查询
* 提供表单,允许用户填写条件
* 分析处理类:带有条件的查询,如果没有条件,就是查询所有功能。

“带有条件查询”使用了“查询所有”servlet
* 获得条件,并传递给dao,在dao中拼写sql语句
* 如果sql语句中存在恒定的条件where .... 继续,如果没有,需要添加where 1=1
* 所有的查询条件,必须先进行非空判断,添加使用and语句追加到sql,使用预处理语句?
* 使用list缓存所有?对应的参数(list是有序的)
* 分页查询
* 1 pageNum : 当前页(浏览器传递)
* 2 pageSize : 每页显示的个数(浏览器传递、数据库使用) 7
* 3 startIndex : 开始索引(数据库使用)
* 算法:startIndex = (pageNum - 1) * pageSize; # 第一页索引从0开始
* 例如:
* 第2页:limit 7,7
* 第6页:limit 35,7
* 分析:浏览器(pageNum,pageSize) --> 数据库(limit startIndex,pageSize)
##### 添加效果
* 4 totalRecord,总记录数(数据库中所有的记录数,select count(1) from ...)
* 5 totalPage,总页数
* 算法1:totalPage = (totalRecord + pageSize - 1) / pageSize;
* totalPage = (totalRecord + (pageSize - 1)) / pageSize
* 思考:51 -- 59 + 9(半组的最大值) --> 10 -- 18 (至少保证一组存在)
* 算法2:
if(totalRecord % pageSize == 0){
totalPage = totalRecord / pageSize; //整除
} else {
totalPage = totalRecord / pageSize + 1; //没有整除,+1意思是存在半页}
* 6.data 数据
##### 添加美化
* 7.start 显示页数的开始位置
* 8.end 显示页数的结束位置
* 目的:显示指定的页数,如果页数过多,会不断的变化
案例的程序编码:
* ebookstore_01_blank.rar ,项目的搭建,空白项目
* ebookstore_02_category.rar,完成分组的添加和查询【最基础】
* ebookstore_03_register.rar,用户注册
* ebookstore_04_active_login.rar,用户的激活与登录
* ebookstore_05_addbook.rar,图书的添加,保存上传图片【开始】
* ebookstore_06_findCategoryBook.rar,查询分类书籍(仅查询)
增删改查CURD (create update read delete)
#################################
* ebookstore_07_condition.rar, 带有条件的查询(分组)
* ebookstore_08_page.rar,分页(分组、条件加分页)
##################################
* ebookstore_09_cart.rar,购物车
* ebookstore_10_buybook.rar 下订单(hibernate 做准备,面向对象)
* ebookstore_11_pay.rar 在线支付(面试)
部分不熟代码:
注册时验证码判断:
//0.1验证验证码
// # 获得session缓存的验证码的信息
String serverVerifyCode = (String) request.getSession().getAttribute("serverVerifyCode");
// # 获得用户提交的数据
String verifyCode = request.getParameter("verifyCode");
if(serverVerifyCode != null){
//服务器缓存了信息
// ## 先删除服务器端缓存的数据
request.getSession().removeAttribute("serverVerifyCode");
// ## 判断用户是否填写正确
if(serverVerifyCode.equalsIgnoreCase(verifyCode)){
//正确 --没有任何返回值,将执行之后的代码
} else {
//不正确
request.setAttribute("message", "验证码填写错误");
request.getRequestDispatcher("/client/register.jsp").forward(request, response);
return ;
}
} else {
//没有缓存--重复提交
request.setAttribute("message", "不能重复提交了");
request.getRequestDispatcher("/client/register.jsp").forward(request, response);
return ;
}
注册时事务的应用:
/**
* 注册用户
* 1.添加用户
* 2.发送邮件
* * 注意:如果邮件发送不成功,用户不能添加(事务)
* @param user
* @return
*/
public boolean registerUser(User user) {
Connection conn = null ;
try {
//1 获得链接
conn = JdbcUtils.getConnection();
// ##1 开启事务
conn.setAutoCommit(false);
//2 添加用户
boolean r = userDao.save(conn,user);
//3发送邮件
MailUtils.send(user);
// ##2提交事务
mitAndCloseQuietly(conn);
return r;
} catch (Exception e) {
// ##3回滚事务
DbUtils.rollbackAndCloseQuietly(conn);
throw new RuntimeException(e.getMessage(),e);
}
}
MD5加密方法
/**
* 获得md5加密的结果
* @param value
* @return
*/
public static String getMD5Value(String value){
if(value == null){
return null;
}
try {
// 1 md5加密加密算法摘要对象
MessageDigest messageDigest = MessageDigest.getInstance("MD5");
// 2 摘要计算
byte[] md5ValueByte = messageDigest.digest(value.getBytes());
// 3 将10进制的数转换为16进制
BigInteger bigInteger = new BigInteger(1, md5ValueByte);
return bigInteger.toString(16);
} catch (Exception e) {
//出错不加密
return value;
}
}
上传图片文件:
enctype="multipart/form-data"
添加图书的处理页面:
//0上传的处理
if(! ServletFileUpload.isMultipartContent(request)){
throw new RuntimeException("操作不支持上传,请重试。

");
}
//1封装数据 --上传
// 1.1创建javabean
Book book = new Book();
try {
// 1.2 上传
// 1.2.1 获得工厂
DiskFileItemFactory fileItemFactory = new DiskFileItemFactory();
// ### 设置临时文件大小
fileItemFactory.setSizeThreshold(1024 * 1024 * 4); // 4M
// ### 设置临时文件存储位置
fileItemFactory.setRepository(new
File(this.getServletContext().getRealPath("/temp")));
// 1.2.2 获得核心类
ServletFileUpload servletFileUpload = new ServletFileUpload(fileItemFactory);
// ### 设置上传路径中文乱码
servletFileUpload.setHeaderEncoding("UTF-8");
// 1.2.3 解析上传内容即request ,FileItem 表单中的每一个表单元素的描述对象
List<FileItem> allFileItem = servletFileUpload.parseRequest(request);
// 1.2.4遍历
for(FileItem fileItem : allFileItem){
//1.2.5判断是否为普通字段
if(fileItem.isFormField()){
// 1.2.6.1 获得普通字段的字段名称 -- 与javabean的属性对应
String fieldName = fileItem.getFieldName();
// 1.2.6.2 获得普通字段的字段值 -- 处理提交内容的中文乱码
String fieldValue = fileItem.getString("UTF-8");
/** 使用BeanUtils工具对指定JavaBean,指定属性,设置指定的内容 */
BeanUtils.setProperty(book, fieldName, fieldValue);
} else {
// @@ 上传内容
// 1.2.7.1 获得上传文件的名称
String uploadFileName = fileItem.getName();
// @@ 处理浏览器兼容
uploadFileName = uploadFileName.substring(stIndexOf(File.separator) + 1);
// @@ 文件重名
uploadFileName = StringUtils.getUUID() + "_"+ uploadFileName;
// 1.2.7.2 保存上传文件
InputStream fileIs = fileItem.getInputStream();
File uploadFile = new File(this.getServletContext().getRealPath("/upload"),uploadFileName);
OutputStream fileOut = new FileOutputStream(uploadFile);
// 流的转换
byte[] buf = new byte[1024];
int len = - 1;
while( (len = fileIs.read(buf)) !=-1 ){
fileOut.write(buf, 0, len);
}
fileOut.close();
fileIs.close();
// 1.2.7.3 清除缓存(临时文件)
fileItem.delete();
// 1.2.7.4 将页面的路径设置到javabean
String imgUrl = "/upload/"+ uploadFileName; // /upload/uuid_feng.jpg
book.setImgUrl(imgUrl);
}
}
// 1.3 处理数据,添加id
book.setId(StringUtils.getUUID());
//2操作 -- 保存
BusinessService service = new BusinessService();
boolean saveSuccess = service.addBook(book);
//3选择视图
if(saveSuccess){
response.getWriter().print("图书添加成功");
} else {
response.getWriter().print("图书没有添加成功");
}
} catch (Exception e) {
// 如果上传的图片存在,将删除
if(book!=null){
if(book.getImgUrl() != null){
//删除
File imageFile = new File(this.getServletContext().getRealPath(book.getImgUrl()));
if(imageFile!=null && imageFile.exists()){
imageFile.delete();
}
}
}
throw new RuntimeException(e.getMessage(),e);
}
}
分页处理 servlet页面部分代码
/** 处理分页数据*/
int pageSize = 2; //每页显示6条
int pageNum = 1;
// ## 处理当前页
String pageNumString = request.getParameter("pageNum");
try {
pageNum = Integer.parseInt(pageNumString);
if(pageNum < 1){
pageNum = 1;
}
} catch (NumberFormatException e) {
}
//2.2查询“带有条件的分类书籍”指定分类的书籍,categoryId分类的编号
Page page =
service.findAllBook(categoryId,bookCondition,pageNum,pageSize); pageBean.java
public class Page {
private int pageNum; //当前页
private int pageSize; //每页显示个数
private int startIndex; //开始索引
private int totalRecord; //总记录数
private int totalPage; //总页数
private List data; //数据
private int start ; //遍历开始数
private int end; //遍历结束数
public Page(int pageNum, int pageSize, int totalRecord) {
// 1 基本值
this.pageNum = pageNum;
this.pageSize = pageSize;
this.totalRecord = totalRecord;
// 2 通过计算获得
// * 总页数
this.totalPage = (totalRecord + pageSize - 1) / pageSize ;
// ### 如果当前大于总页数
if(this.pageNum > this.totalPage) {
this.pageNum = this.totalPage;
}
// ##处理如果当前页小于1
if(this.pageNum < 1){
this.pageNum = 1;
}
// * 开始索引
this.startIndex = (this.pageNum - 1) * pageSize;
// 3 处理特殊值
this.start = 1;
this.end = 10;
if(this.totalPage <= 10){
this.end = this.totalPage;
} else {
//大于10页
this.start = this.pageNum - 4;
this.end = this.pageNum + 5;
//开始
if(this.start < 1){
this.start = 1;
this.end = 10;
}
//结束
if(this.end > this.totalPage){
this.end = this.totalPage;
this.start = this.totalPage - 9;
}
}
}
.................
Cart.java 购物车的javabean
/**
* 购物车:
* * 1.存在多个购物项
* * 2.存在一个总价
* @author lt
*
*/
public class Cart {
//1.存在多个购物项 (集合) -- 快速定位 Map , get(key)
// * key : bookId 所要买书籍的id
// * value: CartItem 购物项
private Map<String,CartItem> data = new HashMap<String,CartItem>();
//2.存在一个总价 (所有购物项中小计的和)
private double price;
/**
* 给购物车添加书籍
* * 第一次点击一本书时,添加一个购物项
* * 从第二次开始,只是给购物项添加数量
* @param book
*/
public void addBook(Book book){
//1 获得购物项
CartItem cartItem = data.get(book.getId());
if(cartItem == null){
//2如果没有,创建购物项,并将quantity 设置1
// 2.1创建购物项
cartItem = new CartItem();
// ** 赋值
cartItem.setBook(book);
cartItem.setQuantity(1);
// 2.2 添加到缓存map
data.put(book.getId(), cartItem);
} else {
//3存在,修改quantity + 1
int quantiy = cartItem.getQuantity() + 1;
cartItem.setQuantity(quantiy);
}
}
// 获得总价的内容
public double getPrice() {
//统计所有小计的和
double sum = 0;
for(String key : data.keySet()){
CartItem cartItem = data.get(key);
//获得小计
sum += cartItem.getPrice();
}
this.price = sum;
return price;
}
.........
cartItem.java 购物项的javabean
/**
* 购物项:一组书籍的描述(特指同一本书,数量为多本)
* * 1 存放书籍信息(Book) 可以获得书籍中的所有属性信息
* * 2 购买的数量 quantity
* * 3 小计当前书籍的单价 * 购买的数量 book.getPrice() * quantity * @author lt
*
*/
public class CartItem {
// 1 存放书籍信息(Book)
private Book book;
// 2 购买的数量
private int quantity;
// 3 小计 ( 当前书籍的单价 * 购买的数量 )
private double price;
public double getPrice() {
//进行小计的统计
this.setPrice(this.book.getPrice() * this.quantity);
return price;
}
Order.java 订单的javabean:
/**
* 订单
* private String id;
private Date createDate;
private double price;
//用户
//订单项(集合)存放数据Set
* @author lt
*/
public class Orders {
private String id; //编号
private Date createDate; //下单时间
private double price; //总价
//当前订单属于哪个用户
private User user; //用户
//当前订单包含哪些订单项
private Set<OrdersItem> ordersItemSet = new HashSet<OrdersItem>();
public String getId() {
return id;
}
orderItem.java 订单项的javabean
/**
* 订单项
* private String id;
// 订单项属于哪个订单
prvaite Orders orders;
// 包含那本书
private Book book;
private int quantity;
private double price;
* @author lt
*/
public class OrdersItem {
private String id ; //编号
//订单项属于哪个订单
private Orders orders; //订单
//订单项包含的书籍
private Book book; //书籍 8
private int quantity; //购买数量 2
private double price; //小计 10
public String getId() {
return id;
}。

相关文档
最新文档