javaweb实战

一、第一阶段

前端页面编写

二、第二阶段

Dao,Service代码编写等

javaEE三层架构

image-20221214170343463

1、先创建书城需要的数据库和表。

2、编写数据库表对应的 JavaBean 对象

3、编写工具类 JdbcUtils

​ 3.1、导入需要的 jar 包

数据库和连接池需要

​ druid-1.1.9.jar

​ mysql-connector-java-5.1.7-bin.jar

以下是测试需要

​ hamcrest-core-1.3.jar

​ junit-4.12.jar

​ 3.2、在 src 源码目录下编写 jdbc.properties 属性配置文件:

1
2
3
4
5
6
username=root
password=root
url=jdbc:mysql://localhost:3306/book
driverClassName=com.mysql.jdbc.Driver
initialSize=5
maxActive=10

​ 3.3、编写 JdbcUtils 工具类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
public class JdbcUtils {
private static DruidDataSource dataSource;
static {
try {
Properties properties = new Properties();
// 读取 jdbc.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 = null;
try {
conn = dataSource.getConnection();
} catch (Exception e) {
e.printStackTrace();
}
return conn;
}
/**
* 关闭连接,放回数据库连接池
* @param conn
*/
public static void close(Connection conn){
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
/**

​ 3.4、JdbcUtils 测试:

1
2
3
4
5
6
7
8
9
10
public class JdbcUtilsTest {
@Test
public void testJdbcUtils(){
for (int i = 0; i < 100; i++){
Connection connection = JdbcUtils.getConnection();
System.out.println(connection);
JdbcUtils.close(connection);
}
}
}

4、编写 BaseDao

导入 DBUtils 的 jar 包commons-dbutils-1.3.jar

BaseDao:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
public abstract class BaseDao {
//使用 DbUtils 操作数据库
private QueryRunner queryRunner = new QueryRunner();
/**
* update() 方法用来执行:Insert\Update\Delete 语句
*
* @return 如果返回-1,说明执行失败<br/>返回其他表示影响的行数
*/
public int update(String sql, Object... args) {
Connection connection = JdbcUtils.getConnection();
try {
return queryRunner.update(connection, sql, args);
} catch (SQLException e) {
e.printStackTrace();
} finally {
JdbcUtils.close(connection);
}
return -1;
}
/**
* 查询返回一个 javaBean 的 sql 语句
*
* @param type 返回的对象类型
* @param sql 执行的 sql 语句
* @param args sql 对应的参数值
* @param <T> 返回的类型的泛型
* @return
*/
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();
} finally {
JdbcUtils.close(con);
}
return null;
}
/**
* 查询返回多个 javaBean 的 sql 语句
*
* @param type 返回的对象类型
* @param sql 执行的 sql 语句
* @param args sql 对应的参数值
* @param <T> 返回的类型的泛型
* @return
*/
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();
} finally {
JdbcUtils.close(con);
}
return null;
}
/**
* 执行返回一行一列的 sql 语句
* @param sql 执行的 sql 语句
* @param args sql 对应的参数值
* @return
*/
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();
} finally {
JdbcUtils.close(conn);
}
return null;
}
}

5、编写 UserDao 和测试

userDao:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public interface UserDao {
/**
* 根据用户名查询用户信息
* @param username 用户名
* @return 如果返回 null,说明没有这个用户。反之亦然
*/
public User queryUserByUsername(String username);
/**
* 根据 用户名和密码查询用户信息
* @param username
* @param password
* @return 如果返回 null,说明用户名或密码错误,反之亦然
*/
public User queryUserByUsernameAndPassword(String username,String password);
/**
* 保存用户信息
* @param user
* @return 返回-1 表示操作失败,其他是 sql 语句影响的行数
*/
public int saveUser(User user);
}

UserDaoImpl 实现类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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());
}
}

UserDao 测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class UserDaoTest {
UserDao userDao = new UserDaoImpl();
@Test
public void queryUserByUsername() {
if (userDao.queryUserByUsername("admin1234") == null ){
System.out.println("用户名可用!");
} else {
System.out.println("用户名已存在!");
}
}
@Test
public void queryUserByUsernameAndPassword() {
if ( userDao.queryUserByUsernameAndPassword("admin","admin1234") == null) {
System.out.println("用户名或密码错误,登录失败");
} else {
System.out.println("查询成功");
}
}
@Test
public void saveUser() {
System.out.println( userDao.saveUser(new User(null,"wzg168", "123456", "wzg168@qq.com")) );
}
}

6、编写 UserService 和测试

UserService 接口:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public interface UserService {
/**
* 注册用户
* @param user
*/
public void registUser(User user);
/**
* 登录
* @param user
* @return 如果返回 null,说明登录失败,返回有值,是登录成功
*/
public User login(User user);
/**
* 检查 用户名是否可用
* @param username
* @return 返回 true 表示用户名已存在,返回 false 表示用户名可用
*/
public boolean existsUsername(String username);
}

UserServiceImpl 实现类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class UserServiceTest {
UserService userService = new UserServiceImpl();
@Test
public void registUser() {
userService.registUser(new User(null, "bbj168", "666666", "bbj168@qq.com"));
userService.registUser(new User(null, "abc168", "666666", "abc168@qq.com"));
}
@Test
public void login() {
System.out.println( userService.login(new User(null, "wzg168", "123456", null)) );
}
@Test
public void existsUsername() {
if (userService.existsUsername("wzg16888")) {
System.out.println("用户名已存在!");
} else {
System.out.println("用户名可用!");
}
}
}

Test

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class UserServiceTest {
UserService userService = new UserServiceImpl();
@Test
public void registUser() {
userService.registUser(new User(null, "bbj168", "666666", "bbj168@qq.com"));
userService.registUser(new User(null, "abc168", "666666", "abc168@qq.com"));
}
@Test
public void login() {
System.out.println( userService.login(new User(null, "wzg168", "123456", null)) );
}
@Test
public void existsUsername() {
if (userService.existsUsername("wzg16888")) {
System.out.println("用户名已存在!");
} else {
System.out.println("用户名可用!");
}
}
}

7、编写 web 层

​ 7.1、实现用户注册的功能

image-20221214174022372

image-20221214174123260

servlet

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class RegistServlet extends HttpServlet {
private UserService userService = new UserServiceImpl();
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException,
IOException {
// 1、获取请求的参数
String username = req.getParameter("username");
String password = req.getParameter("password");
String email = req.getParameter("email");
String code = req.getParameter("code");
// 2、检查 验证码是否正确 === 写死,要求验证码为:abcde
if ("abcde".equalsIgnoreCase(code)) {
// 3、检查 用户名是否可用
if (userService.existsUsername(username)) {
System.out.println("用户名[" + username + "]已存在!");
// 跳回注册页面
req.getRequestDispatcher("/pages/user/regist.html").forward(req, resp);
} else {
// 可用
// 调用 Sservice 保存到数据库
userService.registUser(new User(null, username, password, email));
// 跳到注册成功页面 regist_success.html
req.getRequestDispatcher("/pages/user/regist_success.html").forward(req, resp);
}
} else {
System.out.println("验证码[" + code + "]错误");
req.getRequestDispatcher("/pages/user/regist.html").forward(req, resp);
}
}
}

​ 7.3、用户登录功能的实现

image-20221214175946069

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public class LoginServlet extends HttpServlet {
private UserService userService = new UserServiceImpl();
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException,
IOException {
// 1、获取请求的参数
String username = req.getParameter("username");
String password = req.getParameter("password");
// 调用 userService.login()登录处理业务
User loginUser = userService.login(new User(null, username, password, null));
// 如果等于 null,说明登录 失败!
if (loginUser == null) {
// 跳回登录页面
req.getRequestDispatcher("/pages/user/login.html").forward(req, resp);
} else {
// 登录 成功
//跳到成功页面 login_success.html
req.getRequestDispatcher("/pages/user/login_success.html").forward(req, resp);
}
}
}

三、第三阶段

  1. 页面 jsp 动态化

    • 在 html 页面顶行添加 page 指令。
    • 修改文件后缀名为:.jsp
    • 使用 IDEA 搜索替换.html 为.jsp(快捷键:Ctrl+Shift+R}
  2. 抽取页面中相同的内容(用静态包含)

    image-20221217162555894

    要求动态basePath

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    <%
    String basePath = request.getScheme()
    + "://"
    + request.getServerName()
    + ":"
    + request.getServerPort()
    + request.getContextPath()
    + "/";
    %>
    <%=basePath%>
    <!--写 base 标签,永远固定相对路径跳转的结果-->
    <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>
  3. 注册错误提示,及表单回显

    image-20221217162658455

    image-20221217162707923

  4. BaseServlet 的抽取

    在实际的项目开发中,一个模块,一般只使用一个 Servlet 程序。

    合并 LoginServlet 和 RegistServlet 程序为 UserServlet 程序

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    public class UserServlet extends HttpServlet {
    private UserService userService = new UserServiceImpl();
    /**
    * 处理登录的功能
    * @param req
    * @param resp
    * @throws ServletException
    * @throws IOException
    */
    protected void login(HttpServletRequest req, HttpServletResponse resp) throws ServletException,
    IOException {
    // 1、获取请求的参数
    String username = req.getParameter("username");
    String password = req.getParameter("password");
    // 调用 userService.login()登录处理业务
    User loginUser = userService.login(new User(null, username, password, null));
    // 如果等于 null,说明登录 失败!
    if (loginUser == null) {
    // 把错误信息,和回显的表单项信息,保存到 Request 域中
    req.setAttribute("msg","用户或密码错误!");
    req.setAttribute("username", username);
    // 跳回登录页面
    req.getRequestDispatcher("/pages/user/login.jsp").forward(req, resp);
    } else {
    // 登录 成功
    //跳到成功页面 login_success.html
    req.getRequestDispatcher("/pages/user/login_success.jsp").forward(req, resp);
    }
    }
    /**
    * 处理注册的功能
    * @param req
    * @param resp
    * @throws ServletException
    * @throws IOException
    */
    protected void regist(HttpServletRequest req, HttpServletResponse resp) throws ServletException,
    IOException {
    // 1、获取请求的参数
    String username = req.getParameter("username");
    String password = req.getParameter("password");
    String email = req.getParameter("email");
    String code = req.getParameter("code");
    // 2、检查 验证码是否正确 === 写死,要求验证码为:abcde
    if ("abcde".equalsIgnoreCase(code)) {
    // 3、检查 用户名是否可用
    if (userService.existsUsername(username)) {
    System.out.println("用户名[" + username + "]已存在!");
    // 把回显信息,保存到 Request 域中
    req.setAttribute("msg", "用户名已存在!!");
    req.setAttribute("username", username);
    req.setAttribute("email", email);
    // 跳回注册页面
    req.getRequestDispatcher("/pages/user/regist.jsp").forward(req, resp);
    } else {
    // 可用
    // 调用 Sservice 保存到数据库
    userService.registUser(new User(null, username, password, email));
    //
    // 跳到注册成功页面 regist_success.jsp
    req.getRequestDispatcher("/pages/user/regist_success.jsp").forward(req, resp);
    }
    } else {
    // 把回显信息,保存到 Request 域中
    req.setAttribute("msg", "验证码错误!!");
    req.setAttribute("username", username);
    req.setAttribute("email", email);
    System.out.println("验证码[" + code + "]错误");
    req.getRequestDispatcher("/pages/user/regist.jsp").forward(req, resp);
    }
    }
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException,
    IOException {
    String action = req.getParameter("action");
    if ("login".equals(action)) {
    login(req, resp);
    } else if ("regist".equals(action)) {
    regist(req, resp);
    }
    }
  5. 使用反射优化大量 else if 代码

    baseServlet:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    package com.atguigu.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 abstract class BaseServlet extends HttpServlet {

    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    String action = req.getParameter("action");
    try {
    // 获取action业务鉴别字符串,获取相应的业务 方法反射对象
    Method method = this.getClass().getDeclaredMethod(action, HttpServletRequest.class, HttpServletResponse.class);
    // System.out.println(method);
    // 调用目标业务 方法
    method.invoke(this, req, resp);
    } catch (Exception e) {
    e.printStackTrace();
    }
    }

    }

    ==让userServlet继承BaseServlet==

  6. 数据的封装和抽取 BeanUtils 的使用

    BeanUtils 工具类,它可以一次性的把所有请求的参数注入到 JavaBean 中。

    BeanUtils 工具类,经常用于把 Map 中的值注入到 JavaBean 中,或者是对象属性值的拷贝操作。

    image-20221217172825898

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    public class WebUtils {
    /**
    * 把 Map 中的值注入到对应的 JavaBean 属性中。
    * @param value
    * @param bean
    */
    public static <T> T copyParamToBean( Map value , T bean ){
    try {
    System.out.println("注入之前:" + bean);
    /**
    * 把所有请求的参数都注入到 user 对象中
    */
    BeanUtils.populate(bean, value);
    System.out.println("注入之后:" + bean);
    } catch (Exception e) {
    e.printStackTrace();
    }
    return bean;
    }
    }

    使用map比HttpServletRequest好(第7行),能在dao层和service中也使用

    image-20221217173508999

    此时一行代码完成注入

四、第四阶段

EL表达式修改表单回显

image-20221217173638083

五、第五阶段

MVC 全称:Model 模型、 View 视图、 Controller 控制器。

MVC 最早出现在 JavaEE 三层中的 Web 层,它可以有效的指导 Web 层的代码如何有效分离,单独工作。

View 视图:只负责数据和界面的显示,不接受任何与显示数据无关的代码,便于程序员和美工的分工合作——JSP/HTML。

Controller 控制器:只负责接收请求,调用业务层的代码处理请求,然后派发页面,是一个“调度者”的角色——Servlet。

转到某个页面。或者是重定向到某个页面。

Model 模型:将与业务逻辑相关的数据封装为具体的 JavaBean 类,其中不掺杂任何与数据处理相关的JavaBean/domain/entity/pojo。

MVC 是一种思想,MVC 的理念是将软件代码拆分成为组件,单独开发,组合使用(目的还是为了降低耦合度)。

image-20221217174736532

添加图书功能的实现BUG:

当用户提交完请求,浏览器会记录下最后一次请求的全部信息。当用户按下功能键 F5,就会发起浏览器记录的最后一次请求。

解决方法:使用重定向

1
2
3
4
5
6
7
8
9
10
11
protected void add(HttpServletRequest req, HttpServletResponse resp) throws ServletException,
IOException {
// 1、获取请求的参数==封装成为 Book 对象
Book book = WebUtils.copyParamToBean(req.getParameterMap(),new Book());
// 2、调用 BookService.addBook()保存图书
bookService.addBook(book);
// 3、跳到图书列表页面
// /manager/bookServlet?action=list
// req.getRequestDispatcher("/manager/bookServlet?action=list").forward(req, resp);
resp.sendRedirect(req.getContextPath() + "/manager/bookServlet?action=list");
}

修改图书

image-20221217180309034

六、第六阶段

分页

image-20221218145008433

分页模型 Page

1
2
3
4
5
6
7
8
9
10
11
12
13
public class Page<T> {
public static final Integer PAGE_SIZE = 4;
// 当前页码
private Integer pageNo;
// 总页码
private Integer pageTotal;
// 当前页显示数量
private Integer pageSize = PAGE_SIZE;
// 总记录数
private Integer pageTotalCount;
// 当前页数据
private List<T> items;
}

分页的初步实现

DAO:

1
2
3
4
5
6
7
8
9
10
11
12
@Override
public Integer queryForPageTotalCount() {
String sql = "select count(*) from t_book";
Number count = (Number) queryForSingleValue(sql);
return count.intValue();
}
@Override
public List<Book> queryForPageItems(int begin, int pageSize) {
String sql = "select `id` , `name` , `author` , `price` , `sales` , `stock` , `img_path` imgPath
from t_book limit ?,?";
return queryForList(Book.class,sql,begin,pageSize);
}

BookService 代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
	@Override
public Page<Book> page(int pageNo, int pageSize) {
Page<Book> page = new Page<Book>();
// 设置当前页码
page.setPageNo(pageNo);
// 设置每页显示的数量
page.setPageSize(pageSize);
// 求总记录数
Integer pageTotalCount = bookDao.queryForPageTotalCount();
// 设置总记录数
page.setPageTotalCount(pageTotalCount);
// 求总页码
Integer pageTotal = pageTotalCount / pageSize;
if (pageTotalCount % pageSize > 0) {
pageTotal+=1;
}
// 设置总页码
page.setPageTotal(pageTotal);
// 求当前页数据的开始索引
int begin = (page.getPageNo() - 1) * pageSize;
// 求当前页数据
List<Book> items = bookDao.queryForPageItems(begin,pageSize);
// 设置当前页数据
page.setItems(items);
return page;
}
BookServlet 程序的代码:
/**
* 处理分页功能
* @param req
* @param resp
* @throws ServletException
* @throws IOException
*/
protected void page(HttpServletRequest req, HttpServletResponse resp) throws ServletException,
IOException {
//1 获取请求的参数 pageNo 和 pageSize
int pageNo = WebUtils.parseInt(req.getParameter("pageNo"), 1);
int pageSize = WebUtils.parseInt(req.getParameter("pageSize"), Page.PAGE_SIZE);
//2 调用 BookService.page(pageNo,pageSize):Page 对象
Page<Book> page = bookService.page(pageNo,pageSize);
//3 保存 Page 对象到 Request 域中
req.setAttribute("page",page);
//4 请求转发到 pages/manager/book_manager.jsp 页面
req.getRequestDispatcher("/pages/manager/book_manager.jsp").forward(req,resp);
}

book_manager.jsp:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
<%@ 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标签绑定单击事件,用于删除的确认提示操作
$("a.deleteClass").click(function () {
// 在事件的function函数中,有一个this对象。这个this对象,是当前正在响应事件的dom对象。
/**
* confirm是确认提示框函数
* 参数是它的提示内容
* 它有两个按钮,一个确认,一个是取消。
* 返回true表示点击了,确认,返回false表示点击取消。
*/
return confirm("你确定要删除【" + $(this).parent().parent().find("td:first").text() + "】?");
// return false// 阻止元素的默认行为===不提交请求
});
});
</script>

</head>
<body>

<div id="header">
<img class="logo_img" alt="" src="../../static/img/logo.gif" >
<span class="wel_word">图书管理系统</span>

<%-- 静态包含 manager管理模块的菜单 --%>
<%@include file="/pages/common/manager_menu.jsp"%>


</div>

<div id="main">
<table>
<tr>
<td>名称</td>
<td>价格</td>
<td>作者</td>
<td>销量</td>
<td>库存</td>
<td colspan="2">操作</td>
</tr>

<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>
<td><a href="manager/bookServlet?action=getBook&id=${book.id}&pageNo=${requestScope.page.pageNo}">修改</a></td>
<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>
</tr>
</table>


<%--静态包含分页条--%>
<%@include file="/pages/common/page_nav.jsp"%>




</div>


<%--静态包含页脚内容--%>
<%@include file="/pages/common/footer.jsp"%>


</body>
</html>

manager_menu.jsp 中【图书管理】请求地址的修改:

image-20221218150357296

WEB层:

1
2
3
4
5
6
7
8
9
10
11
12
protected void page(HttpServletRequest req, HttpServletResponse resp) throws ServletException,
IOException {
//1 获取请求的参数 pageNo 和 pageSize
int pageNo = WebUtils.parseInt(req.getParameter("pageNo"), 1);
int pageSize = WebUtils.parseInt(req.getParameter("pageSize"), Page.PAGE_SIZE);
//2 调用 BookService.page(pageNo,pageSize):Page 对象
Page<Book> page = bookService.page(pageNo,pageSize);
//3 保存 Page 对象到 Request 域中
req.setAttribute("page",page);
//4 请求转发到 pages/manager/book_manager.jsp 页面
req.getRequestDispatcher("/pages/manager/book_manager.jsp").forward(req,resp);
}

首页、上一页、下一页、末页实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<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>
<a href="#">3</a>
【${ requestScope.page.pageNo }】
<a href="#">5</a>
<%-- 如果已经 是最后一页,则不显示下一页,末页 --%>
<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="4" name="pn" id="pn_input"/>页
<input type="button" value="确定">
</div>