JavaWeb书城项目
一、前言
-
本项目是我学习JavaWeb阶段,完成的实现了客户端、服务器、数据库三者交互的web项目。作为学习框架阶段对JavaWeb相关知识点的回顾,在此梳理。 -
项目中运用到的知识点有:javase、servlet程序、jsp页面、JavaScript、jQuery框架、CSS样式、EL表达式、JSTL标签库、 Filter过滤器、jsp四大域对象、JDBC、MySql -
由于文章使用Markdown语法书写且文章较长,pc端观看效果最佳(其实只是有无目录区别)
二、项目主页及编译器界面展示
(1)项目主页
(2)编译器主页
本项目并未使用ssm或springboot等框架(以及maven项目管理),由手动实现web,service,dao三层架构
解释一下src目录和web目录下的包和子目录内容(从上到下):
- src:
filter-配置过滤器 impl-dao层(持久层)接口及实现类 pojo-bean目录 service-service层(业务逻辑层)接口及实现类 test-dao层和service层实现类的测试 utils-JDBC和web层的工具类 web-web层(表现层)的servlet程序 jdbc.properties-数据库配置文件 - web:
pages-各jsp页面 static-css样式,图片,jQuery框架源码 WEB.INF-项目所依赖的jar包和xml配置文件 - 右侧为本项目所用到的数据库book
三、项目实现
1.项目准备
(1)导入所需jar包和资源文件
commons-beanutils-1.8.0.jar
commons-dbutils-1.3.jar
commons-logging-1.1.1.jar
druid-1.1.9.jar
hamcrest-core-1.3.jar
junit-4.12.jar
hamcrest-core-1.3.jar
mysql-connector-java-8.0.27.jar
gson-2.2.4.jar
Java EE 6-Java EE 6
kaptcha-2.3.2.jar
taglibs-standard-impl-1.2.1.jar
taglibs-standard-spec-1.2.1.jar
(时间久远,可能有遗漏) jdk用的是17.0.1,Tomcat版本为:Tomcat8.0.50
(2)创建所需数据库,数据表
- t_book:图书信息表
- t_order:订单信息表
- t_order:订单项信息表
- t_user:用户信息表
(3) 编写jdbc.properties配置文件
username=root
password=123456789(这里瞎写了一波)
url=jdbc:mysql://localhost:3306/book
driverClassName=com.mysql.cj.jdbc.Driver
initialSize=5
maxActive=10
2.项目工具类及配置文件编写
(1)编写工具类
- JDBC工具类的编写
此类主要负责: 通过数据库连接池获取数据库连接 关闭数据库连接(由于处理事务,顺便进行提交和回滚) 用到了Apache组织下的dbutils工具类
package utils;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;
public class JdbcUtils {
private static DruidDataSource dataSource;
private static ThreadLocal<Connection> conns = new ThreadLocal<>();
static {
try {
Properties properties = new Properties();
InputStream inputStream = JdbcUtils.class.getClassLoader().getResourceAsStream("jdbc.properties");
properties.load(inputStream);
dataSource = (DruidDataSource) DruidDataSourceFactory.createDataSource(properties);
} catch (Exception e) {
e.printStackTrace();
}
}
public static Connection getConnection() {
Connection conn = conns.get();
if (conn == null) {
try {
conn = dataSource.getConnection();
conns.set(conn);
conn.setAutoCommit(false);
} catch (SQLException e) {
e.printStackTrace();
}
}
return conn;
}
public static void commitAndClose() {
Connection connection = conns.get();
if (connection != null) {
try {
connection.commit();
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
conns.remove();
}
public static void rollbackAndClose() {
Connection connection = conns.get();
if (connection != null) {
try {
connection.rollback();
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
conns.remove();
}
}
- web层工具类的编写(1)
此页面主要负责: 将服务器发送来的get请求转为post请求 获取jsp页面请求的servlet类和方法(action) 通过反射的方式调用指定servlet类中的指定方法(invoke)
package web;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Method;
public class BaseServlet extends HttpServlet {
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String action = req.getParameter("action");
try {
Method declaredMethod = this.getClass().getDeclaredMethod(action,HttpServletRequest.class,HttpServletResponse.class);
declaredMethod.invoke(this,req,resp);
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
doPost(req,resp);
}
}
- web工具类的编写(2)
此类主要负责: 获取web层传来的 封装为Map对象的客户端请求,将其封装为Bean对象再传回web层 获取web层传来的 获取数据类型为String的id号,将其转化为int型再传回web层 (其实也可以写在web层的servlet程序中,但为了方便每个servlet程序调用,将这俩个方法封装为工具类)
package utils;
import org.apache.commons.beanutils.BeanUtils;
import java.util.Map;
public class WebUtils {
public static <T> T copyParameterToBean(Map value, T bean) {
try {
BeanUtils.populate(bean, value);
} catch (Exception e) {
}
return bean;
}
public static int parseInt(String id, int defaultValue) {
try {
return Integer.parseInt(id);
} catch (Exception e) {
e.printStackTrace();
}
return defaultValue;
}
}
- DAO层工具类编写
此类主要负责: 调用JDBCUtils中的获取和关闭连接操作以及dbutils数据库连接池中的方发 用其封装成基本的更改和查询操作
package impl;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.apache.commons.dbutils.handlers.ScalarHandler;
import utils.JdbcUtils;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
public abstract class BaseDao {
private QueryRunner queryRunner = new QueryRunner();
public int update(String sql, Object... args) {
Connection connection = JdbcUtils.getConnection();
try {
return queryRunner.update(connection, sql, args);
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
public <T> T queryForOne(Class<T> type, String sql, Object... args) {
Connection con = JdbcUtils.getConnection();
try {
return queryRunner.query(con, sql, new BeanHandler<T>(type), args);
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
public <T> List<T> queryForList(Class<T> type, String sql, Object... args) {
Connection con = JdbcUtils.getConnection();
try {
return queryRunner.query(con, sql, new BeanListHandler<T>(type), args);
} catch (SQLException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
public Object queryForSingleValue(String sql, Object... args){
Connection conn = JdbcUtils.getConnection();
try {
return queryRunner.query(conn, sql, new ScalarHandler(), args);
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
}
(2)编写配置文件
xml配置文件的编写 注:(这个步骤按顺序来说应该在配置servlet程序,filter过滤器,google验证码,异常跳转时编写,但由于工具类中需要用到配置的地址,所以我将它放在这里) 此步骤指名了各servlet程序的类名及路径 指名了filter过滤器所拦截的页面地址 导入了google验证码 设置了异常跳转路径
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<servlet>
<servlet-name>RegisterServlet</servlet-name>
<servlet-class>web.older.RegisterServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>RegisterServlet</servlet-name>
<url-pattern>/registerServlet</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>LoginServlet</servlet-name>
<servlet-class>web.older.LoginServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>LoginServlet</servlet-name>
<url-pattern>/loginServlet</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>UserServlet</servlet-name>
<servlet-class>web.UserServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>UserServlet</servlet-name>
<url-pattern>/userServlet</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>BookServlet</servlet-name>
<servlet-class>web.BookServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>BookServlet</servlet-name>
<url-pattern>/manager/bookServlet</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>ClientBookServlet</servlet-name>
<servlet-class>web.ClientBookServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ClientBookServlet</servlet-name>
<url-pattern>/client/bookServlet</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>KaptchaServlet</servlet-name>
<servlet-class>com.google.code.kaptcha.servlet.KaptchaServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>KaptchaServlet</servlet-name>
<url-pattern>/kaptcha.jpg</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>CartServlet</servlet-name>
<servlet-class>web.CartServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>CartServlet</servlet-name>
<url-pattern>/cartServlet</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>OrderServlet</servlet-name>
<servlet-class>web.OrderServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>OrderServlet</servlet-name>
<url-pattern>/orderServlet</url-pattern>
</servlet-mapping>
<filter>
<filter-name>ManagerFilter</filter-name>
<filter-class>filter.ManagerFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>ManagerFilter</filter-name>
<url-pattern>/pages/manager/*</url-pattern>
<url-pattern>/manager/bookServlet</url-pattern>
</filter-mapping>
<filter>
<filter-name>TransactionsFilter</filter-name>
<filter-class>filter.TransactionFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>TransactionsFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<error-page>
<error-code>500</error-code>
<location>/pages/error/error500.jsp</location>
</error-page>
<error-page>
<error-code>404</error-code>
<location>/pages/error/error404.jsp</location>
</error-page>
</web-app>
(3)编写jsp页面公共部分
- 所有页面的head文件
此文件主要负责: 帮助每个页面获取动态的URL地址 为每个页面添加静态包含base标签,css样式,jquery文件
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%--动态获取地址URL--%>
<%
String basePath =
request.getScheme()
+"://"
+request.getServerName()
+":"
+request.getServerPort()
+request.getContextPath()
+"/";
pageContext.setAttribute("basePath",basePath);
%>
<base href="<%=basePath%>">
<link type="text/css" rel="stylesheet" href="static/css/style.css" >
<script type="text/javascript" src="static/script/jquery-1.7.2.js"></script>
- 所有页面的foot文件
此页面主要负责: 引入底部标签
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<div id="bottom">
<span>
OdinPeng.BookStore ©2021
</span>
</div>
- 当登录成功后,各页面显示的信息栏
通过session域获取客户端保存的登录名 给各按钮指定跳转页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<div>
<span>欢迎<span class="um_span">${sessionScope.user.username}</span>光临Google书城</span>
<a href="../order/order.jsp">我的订单</a>
<a href="userServlet?action=logout">注销</a>
<a href="index.jsp">返回</a>
</div>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<div>
<a href="manager/bookServlet?action=page">图书管理</a>
<a href="pages/manager/order_manager.jsp">订单管理</a>
<a href="index.jsp">返回商城</a>
</div>
3.各页面实现及动态展示
(1)登录页面功能实现
-
页面展示: 首先使用错误测试,再使用正确密码测试 -
分析: 登录功能实现的要素:用户名要存在,密码要正确 所以用户在输入username和password 提交之后,我们得将请求发送给服务器。由服务器接收请求数据并访问本地数据库对应的用户信息表,对其信息进行查询。并将查询结果原路返回,直到servlet层进行判断。若是从数据库中查询到的用户信息与请求信息相符,则登录成功。若不相符,则保留用户名,删除密码,让用户重新输入。 首先创建User的bean类 这个阶段的实现需要JavaWeb三层架构,dao层用来封装基本的JDBC查询程序,service用来封装web层所需要的查询逻辑方法。web层则用来接收客户端发送的数据请求,并调用service层方法来进行判断用户信息是否吻合。 我将由从下到上的顺序(dao->service->web)为大家介绍此功能的实现: -
定义User的Bean类 注:(为了节省空间且bean目录中代码大同小异,文章中只展现User的bean文件)
package pojo;
public class User {
private Integer id;
private String username;
private String password;
private String email;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
@Override
public String toString() {
return "User{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
", email='" + email + '\'' +
'}';
}
public User() {
}
public User(Integer id, String username, String password, String email) {
this.id = id;
this.username = username;
this.password = password;
this.email = email;
}
}
- dao层
(1)定义userDao接口: 规定需要定义的方法:queryUserByUsername (queryUserByUsername和savaUser方法注册界面需要使用)
package impl;
import pojo.User;
public interface UserDao {
public User queryUserByUsername(String username);
public User queryUserByUsernameAndPassword(String username,String password);
public int saveUser(User user);
}
(2)UserDao接口实现类: 调用BaseDao定义的方法,实现UserDao接口
package impl;
import pojo.User;
public class UserDaoImpl extends BaseDao implements UserDao {
@Override
public User queryUserByUsername(String username) {
String sql = "select `id`,`username`,`password`,`email` from t_user where username = ?";
return queryForOne(User.class, sql, username);
}
@Override
public User queryUserByUsernameAndPassword(String username, String password) {
String sql = "select `id`,`username`,`password`,`email` from t_user where username = ? and password = ?";
return queryForOne(User.class, sql, username,password);
}
@Override
public int saveUser(User user) {
String sql = "insert into t_user(`username`,`password`,`email`) values(?,?,?)";
return update(sql, user.getUsername(),user.getPassword(),user.getEmail());
}
}
- service层
(1)定义UserService接口
package service;
import pojo.User;
public interface UserService {
public void registerUser(User user);
public User login(User user);
public boolean existsUsername(String username);
}
(2)UserService接口实现类
package service;
import impl.UserDao;
import impl.UserDaoImpl;
import pojo.User;
public class UserServiceImpl implements UserService{
private UserDao userDao=new UserDaoImpl();
@Override
public void registerUser(User user) {
userDao.saveUser(user);
}
@Override
public User login(User user) {
return userDao.queryUserByUsernameAndPassword(user.getUsername(), user.getPassword());
}
@Override
public boolean existsUsername(String username) {
if (userDao.queryUserByUsername(username)==null){
return false;
}else{
return true;
}
}
}
- Web层
实现UserServlet程序,接收客户端发送的数据请求,并调用service层方法来进行判断用户信息是否符合。并响应给客户端。 注:
package web;
import pojo.User;
import service.UserService;
import service.UserServiceImpl;
import utils.WebUtils;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import static com.google.code.kaptcha.Constants.KAPTCHA_SESSION_KEY;
public class UserServlet extends BaseServlet {
private UserService userService = new UserServiceImpl();
protected void login(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String username = req.getParameter("username");
String password = req.getParameter("password");
User login = userService.login(new User(null, username, password, null));
if (login != null) {
System.out.println("登录成功!");
req.getSession().setAttribute("user",login);
req.getRequestDispatcher("/pages/user/login_success.jsp").forward(req, resp);
} else {
System.out.println("用户名或密码不正确,登录失败!");
req.setAttribute("msg","用户名或密码不正确!");
req.setAttribute("username",username);
req.getRequestDispatcher("/pages/user/login.jsp").forward(req, resp);
}
}
}
<form action="userServlet" method="post">
<input type="hidden" name="action" value="login"/>
注:由上文的baseServlet类和xml配置文件得知: 这两行代码指定了此页面内容提交后将客户端发送的请求数据发送到指定的Servlet程序里,将hidden类型input标签的action属性值发送给BaseServlet,利用反射,调用action属性值指名的servlet程序方法
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Google会员登录页面</title>
<%--导入静态包含base标签,css样式,jquery文件--%>
<%@include file="/pages/common/head.jsp"%>
</head>
<body>
<div id="login_header">
<img class="logo_img" alt="" src="static/img/google.gif" height="88" width="365" style="margin-left: -120px">
</div>
<div class="login_banner">
<div id="l_content">
<span class="login_word">欢迎登录</span>
</div>
<div id="content">
<div class="login_form">
<div class="login_box">
<div class="tit">
<h1>Google会员</h1>
<a href="pages/user/regist.jsp">立即注册</a>
</div>
<div class="msg_cont">
<b></b>
<span class="errorMsg">
<%--<%=request.getAttribute("msg")==null?"请输入用户名和密码" :request.getAttribute("msg")%>--%>
<%--EL表达式写法:--%>
${empty requestScope.msg ? "请输入用户名和密码" : requestScope.msg}
</span>
</div>
<div class="form">
<form action="userServlet" method="post">
<input type="hidden" name="action" value="login"/>
<label>用户名称:</label>
<input class="itxt" type="text" placeholder="请输入用户名" autocomplete="off" tabindex="1" name="username"
<%--value="<%=request.getAttribute("username")==null?"":request.getAttribute("username")%>"--%>
value="${requestScope.username}"
/>
<br />
<br />
<label>用户密码:</label>
<input class="itxt" type="password" placeholder="请输入密码" autocomplete="off" tabindex="1" name="password" />
<br />
<br />
<input type="submit" value="登录" id="sub_btn" />
</form>
</div>
</div>
</div>
</div>
</div>
<%--导入底部标签--%>
<%@include file="/pages/common/footer.jsp"%>
</body>
</html>
(2)注销功能实现
protected void logout(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
req.getSession().invalidate();
resp.sendRedirect(req.getContextPath());
}
<div id="header">
<img class="logo_img" alt="" src="static/img/google.gif" height="88" width="365">
<span class="wel_word">BOOK STORE</span>
<div>
<%--如果未登录,sessionScope.user内容为空,则显示登录,注册按钮--%>
<c:if test="${ empty sessionScope.user}">
<a href="pages/user/login.jsp">[登录]</a> |
<a href="pages/user/regist.jsp">[注册]</a>
</c:if>
<c:if test="${ not empty sessionScope.user}">
欢迎<span class="um_span">${sessionScope.user.username}</span>
<%--<a href="../order/order.jsp">[订单]</a>--%>
<a href="userServlet?action=logout">[注销]</a>
</c:if>
<a href="pages/cart/cart.jsp">[购物车]</a>
<a href="pages/manager/manager.jsp">[后台管理]</a>
</div>
</div>
(3)注册页面功能实现
-
页面展示: 首先使用已存在用户名测试,再使用错误验证码测试,再使用不存在且正确验证码测试 -
分析: 实现登录页面要素为:用户名,密码,邮箱格式符合要求 用户名可用,密码和确认密码相同,验证码输入正确 若用户输入的内容格式正确,验证码也正确,则会将用户的用户名发送给servlet程序,web层将用户名传入dao层。dao层程序访问本地数据库查询是否有与传入用户名相符的用户名,将结果原路返回传入servlet程序。判断与客户端的请求参数是否相符,若不相符则说明用户名可用。若相符则说明用户名已存在,刷新页面,删除用户原有数据。 javaweb三层架构与登录页面相似,代码见上述 -
web层:
protected void regist(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String username = req.getParameter("username");
String password = req.getParameter("password");
String email = req.getParameter("email");
String code = req.getParameter("code");
String sessionCode =(String) req.getSession().getAttribute(KAPTCHA_SESSION_KEY);
req.getSession().removeAttribute(KAPTCHA_SESSION_KEY);
User user = WebUtils.copyParameterToBean(req.getParameterMap(),new User());
boolean b = sessionCode.equalsIgnoreCase(code);
if (b) {
boolean b1 = userService.existsUsername(username);
if (b1) {
System.out.println("用户名已存在!");
req.setAttribute("msg","用户名已存在!");
req.getRequestDispatcher("/pages/user/regist.jsp").forward(req, resp);
} else {
System.out.println("注册成功!");
userService.registerUser(new User(null, username, password, email));
req.getRequestDispatcher("/pages/user/regist_success.jsp").forward(req,resp);
}
}else {
System.out.println("验证码错误!");
req.setAttribute("msg","验证码错误!");
req.setAttribute("username",username);
req.setAttribute("email",email);
req.getRequestDispatcher("/pages/user/regist.jsp").forward(req, resp);
}
}
<input class="itxt" type="text" style="width: 150px;" name="code" id="code"/>
<%--获取获取谷歌验证码--%>
<img alt="" id="code_img" src="kaptcha.jpg" style="float: right; margin-right: 40px; width: 80px; height: 40px">
注:这两行代码为验证码的获取与输入。验证码的获取由 google提供的 kaptcha-2.3.2.jar 包实现,在jsp页面的头文件中,利用javaScript绑定了切换验证码的 单机事件,用户点击图片即可切换。
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Google会员注册页面</title>
<%--导入静态包含base标签,css样式,jquery文件--%>
<%@include file="/pages/common/head.jsp"%>
<script type="text/javascript">
$(function () {
$("#code_img").click(function () {
this.src="${basePath}kaptcha.jpg?d="+new Date();
});
$("#sub_btn").click(function () {
var usernameText = $("#username").val();
var usernamePatt = /^\w{5,12}$/;
if (!usernamePatt.test(usernameText)) {
$("span.errorMsg").text("用户名不合法!");
return false;
}
var passwordText = $("#password").val();
var passwordPatt = /^\w{5,12}$/;
if (!passwordPatt.test(passwordText)) {
$("span.errorMsg").text("密码不合法!");
return false;
}
var repwdText = $("#repwd").val();
if (repwdText != passwordText) {
$("span.errorMsg").text("确认密码和密码不一致!");
return false;
}
var emailText = $("#email").val();
var emailPatt = /^[a-z\d]+(\.[a-z\d]+)*@([\da-z](-[\da-z])?)+(\.{1,2}[a-z]+)+$/;
if (!emailPatt.test(emailText)) {
$("span.errorMsg").text("邮箱格式不合法!");
return false;
}
var codeText = $("#code").val();
codeText = $.trim(codeText);
if (codeText == null || codeText == "") {
$("span.errorMsg").text("验证码不能为空!");
return false;
}
$("span.errorMsg").text("");
});
});
</script>
<style type="text/css">
.login_form{
height:420px;
margin-top: 25px;
}
</style>
</head>
<body>
<div id="login_header">
<img class="logo_img" alt="" src="static/img/google.gif" height="88" width="365" style="margin-left: -120px" >
</div>
<div class="login_banner">
<div id="l_content">
<span class="login_word">欢迎注册</span>
</div>
<div id="content">
<div class="login_form">
<div class="login_box">
<div class="tit">
<h1>注册Google会员</h1>
<span class="errorMsg">
<%--<%=request.getAttribute("msg")==null?"":request.getAttribute("msg")%>--%>
<%--EL表达式写法:--%>
${requestScope.msg}
</span>
</div>
<div class="form">
<form action="userServlet" method="post">
<input type="hidden" name="action" value="regist"/>
<label>用户名称:</label>
<input class="itxt" type="text" placeholder="请输入用户名" autocomplete="off" tabindex="1" name="username" id="username"
<%--value="<%=request.getAttribute("username")==null?"":request.getAttribute("username")%>"--%>
value="${requestScope.username}"
/>
<br />
<br />
<label>用户密码:</label>
<input class="itxt" type="password" placeholder="请输入密码" autocomplete="off" tabindex="1" name="password" id="password" />
<br />
<br />
<label>确认密码:</label>
<input class="itxt" type="password" placeholder="确认密码" autocomplete="off" tabindex="1" name="repwd" id="repwd" />
<br />
<br />
<label>电子邮件:</label>
<input class="itxt" type="text" placeholder="请输入邮箱地址" autocomplete="off" tabindex="1" name="email" id="email"
<%--value="<%=request.getAttribute("email")==null?"":request.getAttribute("email")%>"--%>
value="${requestScope.email}"
/>
<br />
<br />
<label>验证码:</label>
<input class="itxt" type="text" style="width: 150px;" name="code" id="code"/>
<%--获取获取谷歌验证码--%>
<img alt="" id="code_img" src="kaptcha.jpg" style="float: right; margin-right: 40px; width: 80px; height: 40px">
<br />
<br />
<input type="submit" value="注册" id="sub_btn" />
</form>
</div>
</div>
</div>
</div>
</div>
<%--导入底部标签--%>
<%@include file="/pages/common/footer.jsp"%>
</body>
</html>
(4)主页面价格筛选实现
protected void pageByPrice(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
int pageNo = WebUtils.parseInt(req.getParameter("pageNo"), 1);
int pageSize= WebUtils.parseInt(req.getParameter("pageSize"), Page.PAGE_SIZE);
int min = WebUtils.parseInt(req.getParameter("min"), 0);
int max = WebUtils.parseInt(req.getParameter("max"), Integer.MAX_VALUE);
Page<Book> page = bookService.pageByPrice(pageNo, pageSize,min,max);
StringBuilder sb = new StringBuilder("client/bookServlet?action=pageByPrice");
if (req.getParameter("min")!=null){
sb.append("&min=").append(req.getParameter("min"));
}
if (req.getParameter("max")!=null){
sb.append("&max=").append(req.getParameter("max"));
}
page.setUrl(sb.toString());
req.setAttribute("page",page);
req.getRequestDispatcher("/pages/client/index.jsp").forward(req,resp);
}
<div class="book_cond">
<form action="client/bookServlet" method="get" style="margin-left: -43px">
<input type="hidden" name="action" value="pageByPrice">
价格:<input id="min" type="text" name="min" value="${param.min}"> 元 -
<input id="max" type="text" name="max" value="${param.max}"> 元
<input type="submit" value="查询" />
</form>
</div>
(5)分页实现
<%--分页操作--%>
<div id="page_nav">
<%--大于首页,才显示--%>
<c:if test="${requestScope.page.pageNo > 1}">
<a href="${ requestScope.page.url }&pageNo=1">首页</a>
<a href="${ requestScope.page.url }&pageNo=${requestScope.page.pageNo-1}">上一页</a>
</c:if>
<%--页码输出的开始--%>
<c:choose>
<%--情况1:如果总页码小于等于5的情况,页码的范围是:1-总页码--%>
<c:when test="${ requestScope.page.pageTotal <= 5 }">
<c:set var="begin" value="1"/>
<c:set var="end" value="${requestScope.page.pageTotal}"/>
</c:when>
<%--情况2:总页码大于5的情况--%>
<c:when test="${requestScope.page.pageTotal > 5}">
<c:choose>
<%--小情况1:当前页码为前面3个:1,2,3的情况,页码范围是:1-5.--%>
<c:when test="${requestScope.page.pageNo <= 3}">
<c:set var="begin" value="1"/>
<c:set var="end" value="5"/>
</c:when>
<%--小情况2:当前页码为最后3个,8,9,10,页码范围是:总页码减4 - 总页码--%>
<c:when test="${requestScope.page.pageNo > requestScope.page.pageTotal-3}">
<c:set var="begin" value="${requestScope.page.pageTotal-4}"/>
<c:set var="end" value="${requestScope.page.pageTotal}"/>
</c:when>
<%--小情况3:4,5,6,7,页码范围是:当前页码减2 - 当前页码加2--%>
<c:otherwise>
<c:set var="begin" value="${requestScope.page.pageNo-2}"/>
<c:set var="end" value="${requestScope.page.pageNo+2}"/>
</c:otherwise>
</c:choose>
</c:when>
</c:choose>
<c:forEach begin="${begin}" end="${end}" var="i">
<c:if test="${i == requestScope.page.pageNo}">
【${i}】
</c:if>
<c:if test="${i != requestScope.page.pageNo}">
<a href="${ requestScope.page.url }&pageNo=${i}">${i}</a>
</c:if>
</c:forEach>
<%--页码输出的结束--%>
<%-- 如果已经 是最后一页,则不显示下一页,末页 --%>
<c:if test="${requestScope.page.pageNo < requestScope.page.pageTotal}">
<a href="${ requestScope.page.url }&pageNo=${requestScope.page.pageNo+1}">下一页</a>
<a href="${ requestScope.page.url }&pageNo=${requestScope.page.pageTotal}">末页</a>
</c:if>
共${ requestScope.page.pageTotal }页,${ requestScope.page.pageTotalCount }条记录
到第<input value="${param.pageNo}" name="pn" id="pn_input"/>页
<input id="searchPageBtn" type="button" value="确定">
<script type="text/javascript">
$(function () {
$("#searchPageBtn").click(function () {
var pageNo = $("#pn_input").val();
<%--var pageTotal = ${requestScope.page.pageTotal};--%>
<%--alert(pageTotal);--%>
location.href = "${pageScope.basePath}${ requestScope.page.url }&pageNo=" + pageNo;
});
});
</script>
</div>
<%--遍历页面商品--%>
<c:forEach items="${requestScope.page.items}" var="book">
<div class="b_list">
<div class="img_div">
<img class="book_img" alt="" src="${book.imgPath}" />
</div>
<div class="book_info">
<div class="book_name">
<span class="sp1">书名:</span>
<span class="sp2">${book.name}</span>
</div>
<div class="book_author">
<span class="sp1">作者:</span>
<span class="sp2">${book.author}</span>
</div>
<div class="book_price">
<span class="sp1">价格:</span>
<span class="sp2">${book.price}</span>
</div>
<div class="book_sales">
<span class="sp1">销量:</span>
<span class="sp2">${book.sales}</span>
</div>
<div class="book_amount">
<span class="sp1">库存:</span>
<span class="sp2">${book.stock}</span>
</div>
<div class="book_add">
<button bookId="${book.id}" class="addToCart">加入购物车</button>
</div>
</div>
</div>
</c:forEach>
(6)购物车实现
1.主页添加商品到购物车实现
package pojo;
import java.math.BigDecimal;
import java.util.Objects;
public class CartItem {
private Integer id;
private String name;
private Integer count;
private BigDecimal price;
private BigDecimal totalPrice;
public CartItem(Integer id, String name, Integer count, BigDecimal price, BigDecimal totalPrice) {
this.id = id;
this.name = name;
this.count = count;
this.price = price;
this.totalPrice = totalPrice;
}
public CartItem() {
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getCount() {
return count;
}
public void setCount(Integer count) {
this.count = count;
}
public BigDecimal getPrice() {
return price;
}
public void setPrice(BigDecimal price) {
this.price = price;
}
public BigDecimal getTotalPrice() {
return totalPrice;
}
public void setTotalPrice(BigDecimal totalPrice) {
this.totalPrice = totalPrice;
}
@Override
public String toString() {
return "CartItem{" +
"id=" + id +
", name='" + name + '\'' +
", count=" + count +
", price=" + price +
", totalPrice=" + totalPrice +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
CartItem cartItem = (CartItem) o;
return Objects.equals(id, cartItem.id) && Objects.equals(name, cartItem.name) && Objects.equals(count, cartItem.count) && Objects.equals(price, cartItem.price) && Objects.equals(totalPrice, cartItem.totalPrice);
}
@Override
public int hashCode() {
return Objects.hash(id, name, count, price, totalPrice);
}
}
package pojo;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.*;
public class Cart {
private Map<Integer,CartItem> items=new LinkedHashMap<Integer,CartItem>();
public Cart(Map<Integer,CartItem> items) {
this.items = items;
}
public Cart() {}
public void addItem(CartItem cartItem){
CartItem item = items.get(cartItem.getId());
if (item==null){
items.put(cartItem.getId(),cartItem);
}else{
item.setCount(cartItem.getCount()+1);
item.setTotalPrice(item.getPrice().multiply(new BigDecimal(item.getCount())));
}
}
public void deleteItem(Integer id){
items.remove(id);
}
public void clear(){
items.clear();
}
public void updateCount(Integer id, Integer count){
CartItem cartItem = items.get(id);
if (cartItem!=null){
cartItem.setCount(count);
cartItem.setTotalPrice(cartItem.getPrice().multiply(new BigDecimal(cartItem.getCount())));
}
}
public Integer getTotalCount() {
Integer totalCount=0;
for(Map.Entry<Integer,CartItem> entry: items.entrySet()){
totalCount += entry.getValue().getCount();
}
return totalCount;
}
public BigDecimal getTotalPrice() {
BigDecimal totalPrice=new BigDecimal(0);
for (Map.Entry<Integer,CartItem> entry : items.entrySet()){
totalPrice=totalPrice.add(entry.getValue().getTotalPrice());
}
return totalPrice;
}
public Map<Integer,CartItem> getItems() {
return items;
}
public void setItems(Map<Integer,CartItem> items) {
this.items = items;
}
@Override
public String toString() {
return "Cart{" +
"totalCount=" + getTotalCount() +
", totalPrice=" + getTotalPrice() +
", items=" + items +
'}';
}
}
private BookService bookService=new BookServiceImpl();
protected void addItem(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
int id = WebUtils.parseInt(req.getParameter("id"), 0);
Book book = bookService.queryBookById(id);
CartItem cartItem=new CartItem(book.getId(),book.getName(),1,book.getPrice(),book.getPrice());
Cart cart =(Cart)req.getSession().getAttribute("cart");
if (cart==null){
cart = new Cart();
req.getSession().setAttribute("cart",cart);
}
cart.addItem(cartItem);
req.getSession().setAttribute("lastItem",cartItem.getName());
String referer = req.getHeader("Referer");
resp.sendRedirect(referer);
}
<div style="text-align: center">
<%--购物车为空时--%>
<c:if test="${empty sessionScope.cart.items}">
<span style="margin-right: 30px">请添加商品</span>
<div style="margin-right: 30px">
<span style="color: red" >当前购物车为空</span>
</div>
</c:if>
<%--购物车非空时--%>
<c:if test="${not empty sessionScope.cart.items}">
<span>您的购物车中有${sessionScope.cart.totalCount}件商品</span>
<div>
您刚刚将<span style="color: red">${sessionScope.lastItem}</span>加入到了购物车中
</div>
</c:if>
</div>
<div class="book_add">
<button bookId="${book.id}" class="addToCart">加入购物车</button>
</div>
2.购物车页面功能实现
- 页面展示:
- 分析:
购物车页面的删除按钮绑定了单机事件,点击确认后,则会调用cartServlet程序中的deleteItem方法将session域中购物车界面指定id的书籍删除,并且会根据session域中图书信息重新计算商品数量和总价(修改和清空同理) 清空购物车同样绑定了单机事件,调用cartServlet程序中的clear方法将sessoin域中购物车界面的所有图书信息删除 修改数量输入框绑定了焦点事件,修改过后点击空白处,则会将当前商品数、当前商品金额修改。并修改总数,总金额 - servlet程序:
package web;
import pojo.Book;
import pojo.Cart;
import pojo.CartItem;
import service.BookService;
import service.BookServiceImpl;
import utils.WebUtils;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class CartServlet extends BaseServlet{
private BookService bookService=new BookServiceImpl();
protected void addItem(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
int id = WebUtils.parseInt(req.getParameter("id"), 0);
Book book = bookService.queryBookById(id);
CartItem cartItem=new CartItem(book.getId(),book.getName(),1,book.getPrice(),book.getPrice());
Cart cart =(Cart)req.getSession().getAttribute("cart");
if (cart==null){
cart = new Cart();
req.getSession().setAttribute("cart",cart);
}
cart.addItem(cartItem);
req.getSession().setAttribute("lastItem",cartItem.getName());
String referer = req.getHeader("Referer");
resp.sendRedirect(referer);
}
protected void deleteItem(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
int id = WebUtils.parseInt(req.getParameter("id"), 0);
Cart cart = (Cart)req.getSession().getAttribute("cart");
if (cart!=null){
cart.deleteItem(id);
}
resp.sendRedirect(req.getHeader("Referer"));
}
protected void clear(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
Cart cart =(Cart) req.getSession().getAttribute("cart");
if (cart!=null){
cart.clear();
}
resp.sendRedirect(req.getHeader("Referer"));
}
protected void updateCount(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
int id = WebUtils.parseInt(req.getParameter("id"), 0);
int count = WebUtils.parseInt(req.getParameter("count"), 1);
Cart cart = (Cart)req.getSession().getAttribute("cart");
if (cart!=null){
cart.updateCount(id,count);
}
resp.sendRedirect(req.getHeader("Referer"));
}
}
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>购物车</title>
<%--导入静态包含base标签,css样式,jquery文件--%>
<%@include file="/pages/common/head.jsp"%>
<script type="text/javascript">
$(function () {
$(".deleteItem").click(function () {
return confirm("你确定要删除【"+$(this).parent().parent().find("td:first").text()+"】吗?");
});
});
$(function () {
$("#clearCart").click(function () {
return confirm("你确定要清空购物车吗?");
});
});
$(function () {
$(".updateCount").change(function () {
var name = $(this).parent().parent().find("td:first").text();
var count =this.value;
var id=$(this).attr("bookId");
if (confirm("你确定要修改商品【"+name+"】的值为:"+count+"吗?")){
location.href="cartServlet?action=updateCount&count="+count+"&id="+id;
}else{
this.value=this.defaultValue;
}
});
});
</script>
</head>
<body>
<div id="header">
<img class="logo_img" alt="" src="static/img/google.gif" height="88" width="345">
<span class="wel_word">购物车</span>
<%--导入成功后导航栏--%>
<%@ include file="/pages/common/login_success_menu.jsp"%>
</div>
<div id="main" style="background: ghostwhite">
<table>
<tr>
<td>商品名称</td>
<td>数量</td>
<td>单价</td>
<td>金额</td>
<td>操作</td>
</tr>
<%--购物车为空--%>
<c:if test="${empty sessionScope.cart.items}">
<tr>
<td colspan="5" >
<a href="index.jsp" style="color: red"> 您的购物车为空!快去逛逛!</a>
</td>
</tr>
</c:if>
<%--购物车非空--%>
<c:if test="${not empty sessionScope.cart.items}">
<%--遍历购物车中的内容--%>
<c:forEach items="${sessionScope.cart.items}" var="entry">
<tr>
<td>${entry.value.name}</td>
<td>
<input type="text" style="width: 25px" class="updateCount"
bookId="${entry.value.id}" value="${entry.value.count}"/>
</td>
<td>${entry.value.price}</td>
<td>${entry.value.totalPrice}</td>
<td><a class="deleteItem" href="cartServlet?action=deleteItem&id=${entry.value.id}">删除</a></td>
</tr>
</c:forEach>
</c:if>
</table>
<%--购物车非空时才输出此内容--%>
<c:if test="${not empty sessionScope.cart.items}">
<div class="cart_info">
<span class="cart_span">购物车中共有<span class="b_count">${sessionScope.cart.totalCount}</span>件商品</span>
<span class="cart_span">总金额<span class="b_price">${sessionScope.cart.totalPrice}</span>元</span>
<span class="cart_span"><a id="clearCart" href="cartServlet?action=clear">清空购物车</a></span>
<span class="cart_span"><a href="orderServlet?action=createOrder">去结账</a></span>
</div>
</c:if>
</div>
<%--导入底部标签--%>
<%@include file="/pages/common/footer.jsp"%>
</body>
</html>
3.结账并生成订单功能实现
public class OrderDaoImpl extends BaseDao implements OrderDao{
@Override
public int saveOrder(Order order) {
String sql="insert into t_order (order_id,create_time,price,status,user_id) values (?,?,?,?,?)";
return update(sql,order.getOrderId(),order.getCreateTime(),
order.getPrice(),order.getStatus(),order.getUserId());
}
}
- 在t_order_item数据库中会生成被购买的图书编号,名称,数量,单价,总价,对应的订单号
t_order_item数据库: dao程序:
public class OrderItemDaoImpl extends BaseDao implements OrderItemDao{
@Override
public int saveOrderItem(OrderItem orderItem) {
String sql="insert into t_order_item (name,count,price,total_price,order_id) values (?,?,?,?,?)";
return update(sql,orderItem.getName(),orderItem.getCount(),orderItem.getPrice(),
orderItem.getTotalPrice(),orderItem.getOrderId());
}
}
public class OrderServiceImpl implements OrderService{
private OrderDao orderDao = new OrderDaoImpl();
private OrderItemDao orderItemDao = new OrderItemDaoImpl();
private BookDao bookDao=new BookDaoImpl();
@Override
public String createOrder(Cart cart, Integer userId) {
String orderId=System.currentTimeMillis()+""+userId;
Order order = new Order(orderId, new Date(), cart.getTotalPrice(), 0, userId);
orderDao.saveOrder(order);
for (Map.Entry<Integer, CartItem> entry:cart.getItems().entrySet()){
CartItem cartItem = entry.getValue();
OrderItem orderItem = new OrderItem(null, cartItem.getName(), cartItem.getCount(),
cartItem.getPrice(), cartItem.getTotalPrice(), orderId);
orderItemDao.saveOrderItem(orderItem);
Book book = bookDao.queryBookById(cartItem.getId());
book.setSales(book.getSales()+cartItem.getCount());
book.setStock(book.getStock()- cartItem.getCount());
bookDao.updateBook(book);
}
cart.clear();
return orderId;
}
}
public class OrderServlet extends BaseServlet{
private OrderService orderService = new OrderServiceImpl();
protected void createOrder(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
Cart cart = (Cart)req.getSession().getAttribute("cart");
User loginUser=(User)req.getSession().getAttribute("user");
if (loginUser==null){
req.getRequestDispatcher("/pages/user/login.jsp").forward(req,resp);
}else{
Integer userId = loginUser.getId();
String orderId = orderService.createOrder(cart, userId);
req.getSession().setAttribute("orderId",orderId);
resp.sendRedirect(req.getContextPath()+"/pages/cart/checkout.jsp");
}
}
}
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>结算页面</title>
<%--导入静态包含base标签,css样式,jquery文件--%>
<%@include file="/pages/common/head.jsp"%>
<style type="text/css">
h1 {
text-align: center;
margin-top: 200px;
}
</style>
</head>
<body>
<div id="header">
<img class="logo_img" alt="" src="static/img/google.gif" height="88" width="365">
<span class="wel_word">结算</span>
<%--导入成功后导航栏--%>
<div>
<a href="manager/bookServlet?action=page">图书管理</a>
<a href="pages/manager/order_manager.jsp">订单管理</a>
<a href="pages/cart/cart.jsp">返回</a>
</div>
</div>
<div id="main">
<h1>你的订单已结算,订单号为: ${sessionScope.orderId}</h1>
</div>
<%--导入底部标签--%>
<%@include file="/pages/common/footer.jsp"%>
</body>
</html>
(7)后台管理实现
1.过滤未登录用户
<filter>
<filter-name>ManagerFilter</filter-name>
<filter-class>filter.ManagerFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>ManagerFilter</filter-name>
<url-pattern>/pages/manager/*</url-pattern>
<url-pattern>/manager/bookServlet</url-pattern>
</filter-mapping>
<filter>
<filter-name>TransactionsFilter</filter-name>
<filter-class>filter.TransactionFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>TransactionsFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
public class TransactionFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
try {
filterChain.doFilter(servletRequest,servletResponse);
JdbcUtils.commitAndClose();
} catch (Exception e) {
JdbcUtils.rollbackAndClose();
e.printStackTrace();
throw new RuntimeException(e);
}
}
}
public class ManagerFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest req=(HttpServletRequest) servletRequest;
Object user = req.getSession().getAttribute("user");
if (user==null){
req.getRequestDispatcher("/pages/user/login.jsp").forward(servletRequest,servletResponse);
}else{
filterChain.doFilter(servletRequest,servletResponse);
}
}
}
2.图书管理页面实现
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>图书管理</title>
<%--图书管理界面--%>
<%--导入静态包含base标签,css样式,jquery文件--%>
<%@include file="/pages/common/head.jsp"%>
<script type="text/javascript">
$(function () {
$("a.deleteClass").click(function () {
return confirm("你确定要删除【"+$(this).parent().parent().find("td:first").text()+"】?");
});
});
</script>
</head>
<body>
<div id="header">
<img class="logo_img" alt="" src="static/img/google.gif" height="88" width="365" >
<span class="wel_word">图书管理系统</span>
<%@include file="../common/manager_menu.jsp"%>
</div>
<div id="main" style="background: ghostwhite">
<table>
<tr>
<td>名称</td>
<td>价格</td>
<td>作者</td>
<td>销量</td>
<td>库存</td>
<td colspan="2">操作</td>
</tr>
<%--遍历request域中保存的book信息--%>
<c:forEach items="${requestScope.page.items}" var="book">
<tr>
<td>${book.name}</td>
<td>${book.price}</td>
<td>${book.author}</td>
<td>${book.sales}</td>
<td>${book.stock}</td>
<%--请求manager/bookServlet页面,使用其getBook方法 并获取id 指名为update操作--%>
<td><a href="manager/bookServlet?action=getBook&id=${book.id}&
pageNo=${requestScope.page.pageNo}">修改</a></td>
<%--请求manager/bookServlet页面,使用其delete方法 并获取id--%>
<td><a class="deleteClass" href="manager/bookServlet?action=delete&id=${book.id}&
pageNo=${requestScope.page.pageNo}">删除</a></td>
</tr>
</c:forEach>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td><a href="pages/manager/book_edit.jsp?pageNo=${requestScope.page.pageTotal}">添加图书</a></td> <%--指名为add操作--%>
</tr>
</table>
<div id="page_nav">
<%--分页操作--%>
<c:if test="${requestScope.page.pageNo >1}">
<a href="manager/bookServlet?action=page&pageNo=1">首页</a>
<a href="manager/bookServlet?action=page&pageNo=${requestScope.page.pageNo-1}">上一页</a>
</c:if>
<%--页码输出--%>
<c:choose>
<%--情况一:总页码数<=5,显示范围:1-总页码 --%>
<c:when test="${requestScope.page.pageTotal<=5}">
<c:set var="begin" value="1"/>
<c:set var="end" value="${requestScope.page.pageTotal}"/>
</c:when>
<%--情况二:总页码>5--%>
<c:when test="${requestScope.page.pageTotal>5}">
<c:choose>
<%--2.1: 当前页码为前三个,页码范围1-5 --%>
<c:when test="${requestScope.page.pageNo<=3}">
<c:set var="begin" value="1"/>
<c:set var="end" value="5"/>
</c:when>
<%--2.2: 当前页面为后三个,页码范围6-10--%>
<c:when test="${requestScope.page.pageNo> requestScope.page.pageTotal-3}">
<c:set var="begin" value="${requestScope.page.pageTotal-4}"/>
<c:set var="end" value="${requestScope.page.pageTotal}"/>
</c:when>
<%--2.3: 页面为4,5,6,7, 页码范围:当前页码-2 —— 当前页码+2 --%>
<c:otherwise>
<c:set var="begin" value="${requestScope.page.pageNo-2}"/>
<c:set var="end" value="${requestScope.page.pageNo+2}"/>
</c:otherwise>
</c:choose>
</c:when>
</c:choose>
<%--输出分页值--%>
<c:forEach begin="${begin}" end="${end}" var="i">
<%--每个显示数字都能够点击,并且跳转到manager/bookServlet--%>
<%--为当前页码时,不可点击,直接显示【i】--%>
<c:if test="${requestScope.page.pageNo==i}">
【${i}】
</c:if>
<%--不为当前页码时,可以点击,并跳转到指定索引页码--%>
<c:if test="${requestScope.page.pageNo!=i}">
<a href="manager/bookServlet?action=page&pageNo=${i}">${i}</a>
</c:if>
</c:forEach>
<c:if test="${requestScope.page.pageNo< requestScope.page.pageTotal}">
<a href="manager/bookServlet?action=page&pageNo=${requestScope.page.pageNo+1}">下一页</a>
<a href="manager/bookServlet?action=page&pageNo=${requestScope.page.pageTotal}">末页</a>
</c:if>
共${requestScope.page.pageTotal}页,${requestScope.page.pageTotalCount}条记录 到第<input value="${param.pageNo}" name="pn" id="pn_input"/>页
<input id="searchPageBtn" type="button" value="确定">
<script>
$(function () {
$("#searchPageBtn").click(function () {
var pageNo= $("#pn_input").val();
var pageTotal=${requestScope.page.pageTotal};
location.href="${pageScope.basePath}manager/bookServlet?action=page&pageNo="+pageNo;
});
})
</script>
</div>
</div>
<%--导入底部标签--%>
<%@include file="/pages/common/footer.jsp"%>
</body>
</html>
3.删除图书功能实现
protected void delete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
String id = req.getParameter("id");
int i = WebUtils.parseInt(id,0);
bookService.deleteBookById(i);
resp.sendRedirect(req.getContextPath() + "/manager/bookServlet?action=page&pageNo="+req.getParameter("pageNo"));
}
4.修改图书和添加图书功能实现
(修改图书) (添加图书)
-
分析: 点击修改按钮后,跳转到编辑图书界面,并调用bookServlet程序中的getBook方法。通过图书的id,查询出该图书的所有信息 将查询出的信息保存在request域中,跳转到book_edit(编辑图书)界面后,再从request域中取出对应key(字段)的值,显示在修改栏中 由于添加图书和修改图书用的是同一个界面,所以需要通过book_edit页面的request域是否有图书对象来判断是添加还是修改操作 若存在图书对象,则为修改操作,调用bookServlet程序中的add方法 若不存在图书对象,则为添加操作,调用bookServlet程序中的update方法 -
bookServlet程序中的add和update方法
(add)
protected void add(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
int pageNo = WebUtils.parseInt(req.getParameter("pageNo"), 0);
pageNo+=1;
Book book = WebUtils.copyParameterToBean(req.getParameterMap(), new Book());
bookService.addBook(book);
resp.sendRedirect(req.getContextPath() + "/manager/bookServlet?action=page&pageNo=" + pageNo);
}
(update)
protected void update(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
Book book = WebUtils.copyParameterToBean(req.getParameterMap(), new Book());
bookService.updateBook(book);
resp.sendRedirect(req.getContextPath() + "/manager/bookServlet?action=page&pageNo="+req.getParameter("pageNo"));
}
(8)界面错误跳转实现
<error-page>
<error-code>500</error-code>
<location>/pages/error/error500.jsp</location>
</error-page>
<error-page>
<error-code>404</error-code>
<location>/pages/error/error404.jsp</location>
</error-page>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
<%@include file="/pages/common/head.jsp"%>
</head>
<body>
<h1 style="font-size: 100px; color: #666666">页面出现异常,请返回</h1>
<a href="index.jsp">返回首页</a>
</body>
</html>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<title>Title</title>
<%@include file="/pages/common/head.jsp"%>
</head>
<body>
<h1 style="font-size: 100px; color: #666666">页面出现异常,请返回</h1>
<a href="index.jsp">返回首页</a>
</body>
</html>
四、总结
|