前言

巩固Servlet+JSP开发模式,做一个比较完整的小项目.

成果图

该项目包含了两个部分,前台和后台。

前台用于显示

image.png

后台用于管理

image.png

该项目可分为5个模块来组成:分类模块,用户模块,图书模块,购买模块,订单模块


搭建环境

建立包结构

image.png

导入开发包

image.png

前台分帧页面

  • index.jsp【没有body标签的】

  <frameset rows="25%,*">
<frame src="${pageContext.request.contextPath}/client/head.jsp"/>
<frame src="${pageContext.request.contextPath}/client/body.jsp"/>
</frameset>
  • head.jsp

 欢迎来到购物中心
  • body是空白的jsp页面

  • 效果:

image.png


后台分帧页面

  • manager.jsp【嵌套了framset标签,也是没有body标签的】

<frameset rows="25%,*">
<frame src="${pageContext.request.contextPath}/background/head.jsp"/>

<frameset cols="15%,*">
<frame src="${pageContext.request.contextPath}/background/left.jsp"/>
<frame src="${pageContext.request.contextPath}/background/body.jsp"/>
</frameset>
</frameset>
  • head.jsp

 后台管理
  • left.jsp

 分类管理 图书管理 订单管理
  • body.jsp是空白的

  • 效果:

image.png

分帧的文件夹目录结构

image.png

值得注意的是:

  • 文件夹的名字不能使用“manager”,不然会出现:403 Access Denied错误

  • frameset标签是可以嵌套的,分列用“cols”,分行用“rows”

导入工具类和方法的代码

  • 过滤中文乱码数据

  • HTML转义

  • DAOFactory

  • JDBC连接池

  • UUID工具类

  • c3p0.xml配置文件

这些代码都可以在我的博客分类:代码库中找到!


分类模块

首先,我们来做分类模块吧

创建实体Category

    private String id;
private String name;
private String description;

//各种setter、getter

在数据库创建表

CREATE TABLE category (

id VARCHAR(40) PRIMARY KEY,
name VARCHAR(10) NOT NULL UNIQUE ,
description VARCHAR(255)


);

编写CategoryDAO

/**
* 分类模块
*  1:添加分类
*  2:查找分类
*  3:修改分类
*
*
* */
public class CategoryImpl {

public void addCategory(Category category) {

QueryRunner queryRunner = new QueryRunner(Utils2DB.getDataSource());

String sql = "INSERT INTO category (id, name, description) VALUES(?,?,?)";
try {
queryRunner.update(sql, new Object[]{category.getId(), category.getName(), category.getDescription()});

} catch (SQLException e) {
throw new RuntimeException(e);
}
}

public Category findCategory(String id) {
QueryRunner queryRunner = new QueryRunner(Utils2DB.getDataSource());
String sql = "SELECT * FROM category WHERE id=?";

try {
Category category = (Category) queryRunner.query(sql, id, new BeanHandler(Category.class));

return category;

} catch (SQLException e) {
throw new RuntimeException(e);
}

}

public List<Category> getAllCategory() {
QueryRunner queryRunner = new QueryRunner(Utils2DB.getDataSource());
String sql = "SELECT * FROM category";

try {
List<Category> categories = (List<Category>) queryRunner.query(sql, new BeanListHandler(Category.class));

return categories;
} catch (SQLException e) {
throw new RuntimeException(e);
}

}
}

测试DAO

public class demo {

@Test
public void add() {

Category category = new Category();
category.setId("2");
category.setName("数据库系列");
category.setDescription("这是数据库系列");

CategoryImpl category1 = new CategoryImpl();
category1.addCategory(category);

}

@Test
public void find() {

String id = "1";
CategoryImpl category1 = new CategoryImpl();
Category category = category1.findCategory(id);

System.out.println(category.getName());
}
@Test
public void getAll() {


CategoryImpl category1 = new CategoryImpl();
List<Category> categories = category1.getAllCategory();

for (Category category : categories) {
System.out.println(category.getName());
}
}

}

抽取成DAO接口

public interface CategoryDao {
void addCategory(Category category);

Category findCategory(String id);

List<Category> getAllCategory();
}

后台页面的添加分类

  • 在超链接上,绑定显示添加分类的页面

  添加分类
  • 显示添加分类的JSP页面

      分类名称:      分类描述:
  • 处理添加分类的Servlet

        if (method.equals("add")) {

try {
//把浏览器带过来的数据封装到bean中
Category category = WebUtils.request2Bean(request, Category.class);
category.setId(WebUtils.makeId());

service.addCategory(category);
request.setAttribute("message", "添加分类成功!");

} catch (Exception e) {
request.setAttribute("message","添加分类失败");
e.printStackTrace();
}
request.getRequestDispatcher("/message.jsp").forward(request, response);

}
  • 效果:

image.png


后台页面的查看分类

  • 在超链接上,绑定处理请求的Servlet

        else if (method.equals("look")) {

List<Category> list = service.getAllCategory();
request.setAttribute("list", list);
request.getRequestDispatcher("/background/lookCategory.jsp").forward(request, response);

}
  • 显示分类页面的JSP

     暂时还没有分类数据哦,请你添加把                          分类名字            分类描述            操作                                  ${category.name}            ${category.description}                             删除                 修改
  • 效果:

image.png


图书模块

分析

在设计图书管理的时候,我们应该想到:图书和分类是有关系的。一个分类可以对应多本图书。

为什么要这样设计?这样更加人性化,用户在购买书籍的时候,用户能够查看相关分类后的图书,而不是全部图书都显示给用户,让用户一个一个去找。

设计实体

    private String id;
private String name;
private String author;
private String description;
private double price;

//记住图片的名称
private String image;

//记住分类的id
private String category_id;

//各种setter和getter

设计数据库表

CREATE TABLE book (
id VARCHAR(40) PRIMARY KEY,
name VARCHAR(10) NOT NULL UNIQUE,
description VARCHAR(255),
author VARCHAR(10),
price FLOAT,
image VARCHAR(100),
category_id VARCHAR(40),
CONSTRAINT category_id_FK FOREIGN KEY (category_id) REFERENCES category (id)

);

编写DAO

/**
* 图书模块
* 1:添加图书
* 2:查看图书
* 3:查找图书的分页数据【图书一般来说有很多,所以要分页】
*/
public class BookDaoImpl {

public void addBook(Book book) {

QueryRunner queryRunner = new QueryRunner(Utils2DB.getDataSource());

String sql = "INSERT INTO book (id,name,description,author,price,image,category_id) VALUES(?,?,?,?,?,?,?)";
try {
queryRunner.update(sql, new Object[]{book.getId(), book.getName(), book.getDescription(), book.getAuthor(), book.getPrice(),book.getImage(), book.getCategory_id()});

} catch (SQLException e) {
throw new RuntimeException(e);
}
}

public Book findBook(String id) {

QueryRunner queryRunner = new QueryRunner(Utils2DB.getDataSource());

String sql = "SELECT * FROM book WHERE id=?";

try {
return (Book) queryRunner.query(sql, id, new BeanHandler(Book.class));
} catch (SQLException e) {
throw new RuntimeException(e);
}
}

/**得到图书的分页数据*/
public List<Book> getPageData(int start, int end) {

QueryRunner queryRunner = new QueryRunner(Utils2DB.getDataSource());

String sql = "SELECT * FROM book limit ?,?";

try {
return (List<Book>) queryRunner.query(sql, new BeanListHandler(Book.class), new Object[]{start, end});
} catch (SQLException e) {
throw new RuntimeException(e);
}
}

/**得到按照分类图书的分页数据*/
public List<Book> getPageData(int start, int end,String category_id) {

QueryRunner queryRunner = new QueryRunner(Utils2DB.getDataSource());

//WHERE字句在limit字句的前边,注意Object[]的参数位置!
String sql = "SELECT * FROM book WHERE category_id=? limit ?,?";

try {
return (List<Book>) queryRunner.query(sql, new BeanListHandler(Book.class), new Object[]{ category_id,start, end});
} catch (SQLException e) {
throw new RuntimeException(e);
}
}

/**
    * 得到图书的总记录数
    */
public int getTotalRecord() {
QueryRunner queryRunner = new QueryRunner(Utils2DB.getDataSource());

String sql = "SELECT COUNT(*) FROM book";

try {
return (int) queryRunner.query(sql, new ScalarHandler());
} catch (SQLException e) {
throw new RuntimeException(e);
}
}

/**
    * 得到分类后图书的总记录数
    * getCategoryTotalRecord
    */
public long getCategoryTotalRecord(String category_id) {

try {
QueryRunner queryRunner = new QueryRunner(Utils2DB.getDataSource());

String sql = "SELECT COUNT(*) FROM book WHERE category_id=?";
return (long) queryRunner.query(sql, category_id, new ScalarHandler());

} catch (SQLException e) {
throw new RuntimeException(e);
}
}

}

测试DAO

public class BookDemo {

BookDaoImpl bookDao = new BookDaoImpl();


@Test

public void add() {
Book book = new Book();
book.setId("5");
book.setName("SQLServer");
book.setAuthor("我也不知道");
book.setImage("33333332432");
book.setPrice(33.22);
book.setDescription("这是一本好书");
book.setCategory_id("2");

bookDao.addBook(book);
}

@Test
public void look() {

List<Book> bookList = bookDao.getPageData(3, 3);

for (Book book : bookList) {
System.out.println(book.getName());
}

List<Book> books = bookDao.getPageData(0,2,"2");

for (Book book : books) {
System.out.println(book.getName());

}
}

@Test
public void find() {
String id = "2";
Book book = bookDao.findBook(id);

System.out.println(book.getName());
}


}

抽取成DAO接口

public interface BookDao {
void addBook(Book book);

Book findBook(String id);

List<Book> getPageData(int start, int end);

List<Book> getPageData(int start, int end, String category_id);

long getTotalRecord();

long getCategoryTotalRecord(String category_id);
}

编写Service层

    /*添加图书*/
public void addBook(Book book) {
bookDao.addBook(book);

}

/*查找图书*/
public Book findBook(String id) {
return bookDao.findBook(id);
}

/*查找图书*/
public Book findBook(String id) {
return bookDao.findBook(id);
}

/*获取图书的分页数据*/
public Page getPageData(String pageNum) {

Page page=null;
if (pageNum == null) {
page = new Page(1, bookDao.getTotalRecord());
} else {
page = new Page(Integer.valueOf(pageNum), bookDao.getTotalRecord());
}

List<Book> books = bookDao.getPageData(page.getStartIndex(), page.getLinesize());
page.setList(books);

return page;

}

/*获取图书分类后的分页数据*/
public Page getPageData(String currentPageCount,String category_id) {

Page page=null;
if (currentPageCount == null) {
page = new Page(1, bookDao.getCategoryTotalRecord(category_id));
} else {
page = new Page(Integer.valueOf(currentPageCount), bookDao.getCategoryTotalRecord(category_id));
}

List<Book> books = bookDao.getPageData(page.getStartIndex(), page.getLinesize(), category_id);
page.setList(books);
return page;

}

后台添加图书

后台要添加图书的时候,应该说明图书的类型是什么。

要想在显示添加图书的页面上知道全部类型的id,就要经过Servlet把类型的集合传送过去

绑定链接

  添加图书

传送类型集合的Servlet

        String method = request.getParameter("method");
BussinessServiceImpl service = new BussinessServiceImpl();

if (method.equals("addUI")) {

List<Category> list = service.getAllCategory();
request.setAttribute("list", list);
request.getRequestDispatcher("/background/addBook.jsp").forward(request, response);

}

显示JSP页面

                              图书名称:                                           作者:                                           图书价钱:                                          类型:                                                                            ${category.name}                                                                             上传图片                                          详细描述

处理表单数据Servlet

else if (method.equals("add")) {

//上传文件和普通数据分割开,封装到Book对象上
Book book = uploadData(request);

book.setId(WebUtils.makeId());
service.addBook(book);
request.setAttribute("message", "添加图书成功");
request.getRequestDispatcher("/message.jsp").forward(request, response);
}
  • uploadData()方法代码

    private Book uploadData(HttpServletRequest request) {

Book book = new Book();
try{

//1.得到解析器工厂
DiskFileItemFactory factory = new DiskFileItemFactory();

//2.得到解析器
ServletFileUpload upload = new ServletFileUpload(factory);

//设置编码
upload.setHeaderEncoding("UTF-8");


//为上传表单,则调用解析器解析上传数据
List<FileItem> list = upload.parseRequest(request); //FileItem

//遍历list,得到用于封装第一个上传输入项数据fileItem对象
for(FileItem item : list){

if(item.isFormField()){

//得到的是普通输入项
String name = item.getFieldName(); //得到输入项的名称
String value = item.getString("UTF-8");

//使用BeanUtils封装数据
BeanUtils.setProperty(book, name, value);
}else{

//得到上传输入项

//得到上传文件名全路径
String filename = item.getName();

//截取文件名
filename = filename.substring(filename.lastIndexOf("\\")+1);

InputStream in = item.getInputStream(); //得到上传数据

int len = 0;
byte buffer[]= new byte[1024];

//如果没有这个目录,就创建它
String savepath = this.getServletContext().getRealPath("/image");
File file = new File(savepath);
if (!file.exists()) {
file.mkdir();
}

FileOutputStream out = new FileOutputStream(savepath + "\\" + filename);
while((len=in.read(buffer))>0){
out.write(buffer, 0, len);
}
//设置图片的名字
book.setImage(filename);

in.close();
out.close();

//关闭临时文件
item.delete();
}
}

}catch (Exception e) {
e.printStackTrace();
}
return book;
}
  • 效果:

image.png


后台显示图书模块

由于我们用的是分页技术,所以我们导入之前写过的Page类和jsp吧.....这些代码可以在我分类的代码库中找到

绑定超链接

  查看图书

Servlet处理请求

        else if (method.equals("look")) {

String currentPageCount = request.getParameter("currentPageCount");
Page page = service.getPageData(currentPageCount);

request.setAttribute("page",page);
request.getRequestDispatcher("/background/listBook.jsp").forward(request, response);
}

显示图书JSP页面

Servlet端传过来的是Page对象,而不是list集合

可以根据记载在Book对象的图片名称,弄一个超链接,超链接指向服务端的图片,这样就可以查看图片了!

     暂时还没有任何图书哦                       书名           作者           价钱           描述           图片           操作                                           ${book.name}               ${book.author}               ${book.price}               ${book.description}                查看图片                                   删除                    修改

效果:

image.png


前台页面

看回我们前台页面的成果图,我们可以把整个body页面看成是三个div

  • body占整个div

  • 导航条是一个div

  • 显示图书的地方是一个div

image.png


设计好大概的布局

  • html代码引入css

    <link rel="stylesheet" href="body.css" type="text/css">
  • HTML三个div

                                这是导航条                              这是书籍的地方                             这是页码
  • CSS代码:

#body {
position: relative;
}


#category {
border: 1px solid #000;
position: absolute;
width: 300px;
height: 400px;
float: left;
left: 200px;
top: 70px;;
}

#bookandpages {
border: 1px solid #000000;
position: absolute;
width: 600px;
height: 600px;;
float: left;
left: 500px;
margin-left: 50px;
}

#books {
border: 1px solid #000;
width: 600px;
height: 550px;;
}

#page {
border: 1px solid #000;
position: absolute;
height: 48px;
width: 600px;
}
  • 大概的布局

image.png


IndexServlet

在显示首页的下部分的时候,应该先去寻找一个Servlet来把数据交给对应的JSP

因为我们的JSP一般都是放在WEB-INF下,是不能直接访问的。还有就是JSP往往是需要我们后台的数据的,因此我们使用Servlet来获取得到数据,再交由JSP来展示就最好不过了。

    <frame src="${pageContext.request.contextPath}/IndexServlet"/>
  • Servlet代码:

        //得到所有的分类数据,给body页面
BussinessServiceImpl service = new BussinessServiceImpl();
List<Category> categories = service.getAllCategory();
request.setAttribute("categories", categories);
String currentPageCount = request.getParameter("currentPageCount");

//得到所有分类的图书,给body页面
Page page = service.getPageData(currentPageCount);
request.setAttribute("page", page);

request.getRequestDispatcher("/client/body.jsp").forward(request,response);

JSP显示数据

              书籍分类 :                                               ${categories.name}                                                                                                                                                                     书名:${book.name}                                        价格:${book.price}                    作者:${book.author}                                    %--这里要清除浮动,十分重要!--%>

CSS代码:

重要的是:如果div浮动都黏贴在一起了,那么在后边多加个div,用于清除浮动效果

#body {
position: relative;
}

#category {
border: 1px solid #000;
position: absolute;
width: 300px;
height: 400px;
float: left;
left: 200px;
top: 70px;;
}

#bookandpages {
border: 1px solid #000000;
position: absolute;
width: 780px;
height: 538px;;
float: left;
left: 500px;
margin-left: 50px;
}

#books{
margin-left: 50px;
margin-top: 30px;
}
#image{
float: left;
}
#bookinfo{
float: left;
}
#page {
height: 62px;
width: 780px;
position: fixed;
margin-left: 549px;
margin-top: 477px;
text-align: center;
line-height: 50px;
}
  • 效果:

image.png


按照分类显示图书

我们可以根据左边的导航条来显示相对应的分类图书。

  • Servlet代码:

        BussinessServiceImpl service = new BussinessServiceImpl();
String currentPageCount = request.getParameter("currentPageCount");
String category_id = request.getParameter("category_id");

Page page = service.getPageData(currentPageCount, category_id);
List<Category> categories = service.getAllCategory();

request.setAttribute("page", page);
request.setAttribute("categories", categories);
request.getRequestDispatcher("/client/body.jsp").forward(request,response);

效果:

image.png


如果文章有错的地方欢迎指正,大家互相交流。习惯在微信看技术文章的同学,可以关注微信公众号:Java3y



更多相关文章

  1. mysql从入门到优化(2)数据的增删改查操作总结
  2. 都想学大数据开发?年轻人耗子尾汁吧~
  3. 社会化海量数据采集爬虫框架搭建
  4. 数据结构之:二分搜索树
  5. 【荐读】基于文本数据的消费者洞察
  6. BigDecima类型数据的处理--Non-terminating decimal expansio
  7. Flyway 助力数据库脚本自动化管理攻略
  8. MySQL单表数据不要超过500万行:是经验数值,还是黄金铁律?
  9. 基于数据的访问控制

随机推荐

  1. xml学习(4) 创建xml 文件
  2. XML—DOM解析案例
  3. XML的解析
  4. xml学习(3) html显示xml
  5. XML包导入和处理XML数据格式|R包
  6. XML—XML解析之SAX
  7. xml学习(2)xml文档树结构图
  8. R语言XML格式数据导入与处理 - ShangFR
  9. xml学习(1)xml的几种文件格式
  10. XML—XML解析之DOM