• JavaWeb 尚硅谷书城项目


    书城项目第一阶段:表单验证

    需求:

            验证用户名:必须由字母,数字下划线组成,并且长度为 5 到 12 位
            验证密码:必须由字母,数字下划线组成,并且长度为 5 到 12 位
            验证确认密码:和密码相同
            邮箱验证:xxxxx@xxx.com
            验证码:现在只需要验证用户已输入。

    代码:

    1. // 页面加载完成之后
    2. $(function () {
    3. // 给注册绑定单击事件
    4. $("#sub_btn").click(function () {
    5. // 验证用户名:必须由字母,数字下划线组成,并且长度为 5 到 12 位
    6. // 1 获取用户名输入框里的内容
    7. var username = $("#username").val();
    8. // 2 创建正则表达式对象
    9. var usernamePatt = /^\w{5,12}$/;
    10. // 3 使用 test 方法验证
    11. if (!usernamePatt.test(username)) {
    12. // 4 提示用户结果
    13. $("span.errorMsg").text("用户名不合法!");
    14. return false;
    15. }
    16. // 验证密码:必须由字母,数字下划线组成,并且长度为 5 到 12 位
    17. // 1 获取用户密码输入框里的内容
    18. var password = $("#password").val();
    19. // 2 创建正则表达式对象
    20. var passwordPatt = /^\w{5,12}$/;
    21. // 3 使用 test 方法验证
    22. if (!passwordPatt.test(password)) {
    23. // 4 提示用户结果
    24. $("span.errorMsg").text("密码不合法!");
    25. return false;
    26. }
    27. // 验证确认密码:和密码相同
    28. // 1 获取正确密码输入框里的内容
    29. var repwd = $("#repwd").val();
    30. // 2 与密码相比较
    31. if (repwd != password) {
    32. // 4 提示用户
    33. $("span.errorMsg").text("确认密码与密码不一致!");
    34. return false;
    35. }
    36. // 邮箱验证:xxxxx@xxx.com
    37. // 1 获取邮箱里的内容
    38. var email = $("#email").val();
    39. // 2 创建正则表达式对象
    40. var emailPatt = /^[a-z\d]+(\.[a-z\d]+)*@([\da-z](-[\da-z])?)+(\.{1,2}[a-z]+)+$/;
    41. // 3 用test方法验证
    42. if (!emailPatt.test(email)) {
    43. $("span.errorMsg").text("邮箱格式不正确!");
    44. return false;
    45. }
    46. // 验证码:现在只需要验证用户已输入。因为还没讲到服务器。验证码生成。
    47. // 1.获取验证码里面的内容
    48. var code = $("#code").val();
    49. // 2.去掉验证码前后空格
    50. code = $.trim(code);
    51. //3.判断全掉空格后的验证码是否为空
    52. if (code == null || code == "") {
    53. // 提示用户
    54. $("span.errorMsg").text("验证码不能为空!");
    55. return false;
    56. }
    57. });
    58. // 给验证码绑定单击事件
    59. $("#code_img").click(function () {
    60. // 在事件响应的 function 函数中有一个 this 对象。
    61. // 这个 this 对象,是当前正在响应事件的 dom 对象
    62. // src 属性表示验证码 img 标签的 图片路径。它可读,可写
    63. this.src="kaptcha.jpg?id=" + new Date();
    64. });
    65. });

    书城第二阶段——用户注册和登陆

    JavaEE 项目的三层架构

     分层的目的是为了解耦。解耦就是为了降低代码的耦合度。方便项目后期的维护和升级。

    包结构

    web
            com.chenyixin.web/servlet/controller
    service 层
            com.chenyixin.service Service 接口包
            com.chenyixin.service.impl Service 接口实现类
    dao 持久层
            com.chenyixin.dao Dao 接口包
            com.chenyixin.dao.impl Dao 接口实现类
    实体 bean 对象         
            com.chenyixin.pojo/entity/domain/bean         JavaBean 类
    测试包         
            com.chenyixin.test/junit
    工具类        
            com.chenyixin.util

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

    思路:

            1.创建数据库book

            2.切换数据库到book

            3.创建表t_user,用于存储用户信息

            4.插入一条数据进行测试

    代码:

    1. CREATE DATABASE book;
    2. USE book;
    3. CREATE TABLE t_user(
    4. id INT PRIMARY KEY AUTO_INCREMENT,
    5. `username` VARCHAR(25) NOT NULL UNIQUE,
    6. `password` VARCHAR(32) NOT NULL,
    7. email VARCHAR(200)
    8. );
    9. INSERT INTO t_user(`username`,`password`,email)
    10. VALUES('admin','admin','admin@123');
    11. SELECT * FROM t_user;

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

    思路:在pojo中编写一个User类

    代码:(构造器与set、get、toString略)

    1. public class User {
    2. private Integer id;
    3. private String username;
    4. private String password;
    5. private String email
    6. }

    3. 编写工具类 JdbcUtils

    3.1 导入需要的 jar 包(数据库和连接池需要)

    druid-1.1.9.jar
    mysql-connector-java-8.0.27.jar
    以下是测试需要:
    hamcrest-core-1.3.jar
    junit-4.12.jar

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

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

    3.3、编写 JdbcUtils 工具类

    思路:

            1.在utils包中创建JdbcUtils类,在其静态代码块中创建数据库连接

            2. 编写 获取数据库连接的方法

            3.编写 关闭数据可连接的方法

    代码:

    1. public class JdbcUtils {
    2. private static DruidDataSource dataSource;
    3. // 在静态代码块中创建数据库连接
    4. static {
    5. try {
    6. // 获取配置文件jdbc.properties对象
    7. Properties properties = new Properties();
    8. //读取jdbc.properties属性配置文件
    9. InputStream inputStream = JdbcUtils.class.getClassLoader().getResourceAsStream("jdbc.properties");
    10. //从流中加载数据
    11. properties.load(inputStream);
    12. //创建数据库连接池
    13. dataSource = (DruidDataSource) DruidDataSourceFactory.createDataSource(properties);
    14. } catch (Exception e) {
    15. e.printStackTrace();
    16. }
    17. }
    18. /**
    19. * 获取数据库连接池中的连接
    20. *
    21. * @return 如果返回 null,说明获取连接失败
      有值就是获取连接成功
    22. */
    23. public static Connection getConnection() {
    24. Connection conn = null;
    25. try {
    26. conn = dataSource.getConnection();
    27. } catch (SQLException e) {
    28. e.printStackTrace();
    29. }
    30. return conn;
    31. }
    32. /**
    33. * 关闭连接,放回数据库连接池
    34. *
    35. * @param connection 放入要关闭的连接对象
    36. */
    37. public static void close(Connection connection) {
    38. try {
    39. if (connection != null) {
    40. connection.close();
    41. }
    42. } catch (SQLException e) {
    43. e.printStackTrace();
    44. }
    45. }
    46. }

    3.4 JdbcUtils 测试

    在tset包中创建JdbcUtilsTest 进行测试

    1. public class JdbcUtilsTest {
    2. public static void main(String[] args) {
    3. for (int i = 0; i < 100; i++) {
    4. Connection conn = JdbcUtils.getConnection();
    5. System.out.println(conn);
    6. JdbcUtils.close(conn);
    7. }
    8. }
    9. }

    4. 编写 BaseDao

    4.1 导入 DBUtils 的 jar 包

            commons-dbutils-1.3.jar

    4.2  编写 BaseDao

    思路

            1.在dao包中创建BaseDao,并在其类中创建DbUtils 操作数据库的对象

            2.编写update方法用于对数据库的增删改

            3.创建 查询返回一个 javaBean 的 sql 语句 的方法

            4.创建 查询返回多个 javaBean 的 sql 语句 的方法

            5.创建 执行返回一行一列的 sql 语句 的方法

    代码:
    1. public abstract class BaseDao {
    2. private final QueryRunner queryRunner = new QueryRunner();
    3. /**
    4. * 用来执行:Insert\Update\Delete 语句
    5. *
    6. * @param sql 传入要执行的sql语句
    7. * @param args 参数列表
    8. * @return 返回-1表示update失败,否则成功
    9. */
    10. public int update(String sql, Object... args) {
    11. Connection conn = JdbcUtils.getConnection();
    12. try {
    13. return queryRunner.update(conn, sql, args);
    14. } catch (SQLException e) {
    15. e.printStackTrace();
    16. } finally {
    17. JdbcUtils.close(conn);
    18. }
    19. return -1;
    20. }
    21. /**
    22. * 查询返回一个 javaBean 的 sql 语句
    23. * @param type 返回的对象类型
    24. * @param sql 执行的 sql 语句
    25. * @param args sql 对应的参数值
    26. * @param 返回的类型的泛型
    27. * @return 若返回为null,则查看失败
    28. */
    29. public T queryForOne(Class type, String sql, Object... args) {
    30. Connection conn = JdbcUtils.getConnection();
    31. try {
    32. return queryRunner.query(conn, sql, new BeanHandler(type), args);
    33. } catch (SQLException e) {
    34. e.printStackTrace();
    35. } finally {
    36. JdbcUtils.close(conn);
    37. }
    38. return null;
    39. }
    40. /**
    41. * 查询返回多个 javaBean 的 sql 语句
    42. *
    43. * @param type 返回的对象类型
    44. * @param sql 执行的 sql 语句
    45. * @param args sql 对应的参数值
    46. * @param 返回的类型的泛型
    47. * @return 若返回为null, 则查看失败
    48. */
    49. public List queryForList(Class type, String sql, Object... args) {
    50. Connection conn = JdbcUtils.getConnection();
    51. try {
    52. queryRunner.query(conn, sql, new BeanListHandler<>(type), args);
    53. } catch (SQLException e) {
    54. e.printStackTrace();
    55. } finally {
    56. JdbcUtils.close(conn);
    57. }
    58. return null;
    59. }
    60. /**
    61. * 执行返回一行一列的 sql 语句
    62. * @param sql 执行的 sql 语句
    63. * @param args sql对应的参数
    64. * @return 若返回为null, 则查看失败
    65. */
    66. public Object queryForSingleValue(String sql,Object... args) {
    67. Connection conn = JdbcUtils.getConnection();
    68. try {
    69. queryRunner.query(conn,sql,new ScalarHandler(),args);
    70. } catch (SQLException e) {
    71. e.printStackTrace();
    72. } finally {
    73. JdbcUtils.close(conn);
    74. }
    75. return null;
    76. }
    77. }

    5. 编写 UserDao 和测试

    思路:

            1.在Dao包中编写UserDao接口

            2.在UserDao接口中编写queryUserByUsername,

                    queryUserByUsernameAndPassword,saveUser抽象方法

            3.在Dao.impl包中编写UserDaoImpl类,并继承BaseDao,实现UserDao

            4.在UserDaoImpl中编写重写UserDao接口中的方法

            5.在test包中创建UserDaoTest进行测试

    BaseDao 接口:

    1. public abstract class BaseDao {
    2. private final QueryRunner queryRunner = new QueryRunner();
    3. /**
    4. * 用来执行:Insert\Update\Delete 语句
    5. *
    6. * @param sql 传入要执行的sql语句
    7. * @param args 参数列表
    8. * @return 返回-1表示update失败,否则成功
    9. */
    10. public int update(String sql, Object... args) {
    11. Connection conn = JdbcUtils.getConnection();
    12. try {
    13. return queryRunner.update(conn, sql, args);
    14. } catch (SQLException e) {
    15. e.printStackTrace();
    16. } finally {
    17. JdbcUtils.close(conn);
    18. }
    19. return -1;
    20. }
    21. /**
    22. * 查询返回一个 javaBean 的 sql 语句
    23. * @param type 返回的对象类型
    24. * @param sql 执行的 sql 语句
    25. * @param args sql 对应的参数值
    26. * @param 返回的类型的泛型
    27. * @return 若返回为null,则查看失败
    28. */
    29. public T queryForOne(Class type, String sql, Object... args) {
    30. Connection conn = JdbcUtils.getConnection();
    31. try {
    32. return queryRunner.query(conn, sql, new BeanHandler(type), args);
    33. } catch (SQLException e) {
    34. e.printStackTrace();
    35. } finally {
    36. JdbcUtils.close(conn);
    37. }
    38. return null;
    39. }
    40. /**
    41. * 查询返回多个 javaBean 的 sql 语句
    42. *
    43. * @param type 返回的对象类型
    44. * @param sql 执行的 sql 语句
    45. * @param args sql 对应的参数值
    46. * @param 返回的类型的泛型
    47. * @return 若返回为null, 则查看失败
    48. */
    49. public List queryForList(Class type, String sql, Object... args) {
    50. Connection conn = JdbcUtils.getConnection();
    51. try {
    52. queryRunner.query(conn, sql, new BeanListHandler<>(type), args);
    53. } catch (SQLException e) {
    54. e.printStackTrace();
    55. } finally {
    56. JdbcUtils.close(conn);
    57. }
    58. return null;
    59. }
    60. /**
    61. * 执行返回一行一列的 sql 语句
    62. * @param sql 执行的 sql 语句
    63. * @param args sql对应的参数
    64. * @return 若返回为null, 则查看失败
    65. */
    66. public Object queryForSingleValue(String sql,Object... args) {
    67. Connection conn = JdbcUtils.getConnection();
    68. try {
    69. queryRunner.query(conn,sql,new ScalarHandler(),args);
    70. } catch (SQLException e) {
    71. e.printStackTrace();
    72. } finally {
    73. JdbcUtils.close(conn);
    74. }
    75. return null;
    76. }
    77. }

    UserDaoImpl 类:

    1. public class UserDaoImpl extends BaseDao implements UserDao {
    2. @Override
    3. public User queryUserByUsername(String username) {
    4. String sql = "select username,password,email from t_user where username=?";
    5. return queryForOne(User.class,sql,username);
    6. }
    7. @Override
    8. public User queryUserByUsernameAndPassword(String username, String password) {
    9. String sql = "select username,password,email from t_user where username=? and password = ?";
    10. return queryForOne(User.class,sql,username,password);
    11. }
    12. @Override
    13. public int saveUser(User user) {
    14. String sql = "insert into t_user(username,password,email) values(?,?,?)";
    15. return update(sql,user.getUsername(),user.getPassword(),user.getEmail());
    16. }
    17. }

    测试类:

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

    6. 编写 UserService 和测试

    思路:

            1.在service包中创建UserService 接口,该接口含有:

                    login                           登录方法

                    regist                          注册方法

                    existsUsername         检查用户名是否存在的方法

            2.在service.impl包中UserServiceImpl类,并实现UserService 接口的所有方法

            3.在test包中创建UserServiceTest类进行测试

                    

    UserService 接口:

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

    UserServiceImpl类:

    1. public class UserServiceImpl implements UserService {
    2. UserDao userDao = new UserDaoImpl();
    3. @Override
    4. public User login(User user) {
    5. return userDao.queryUserByUsernameAndPassword(user.getUsername(), user.getPassword());
    6. }
    7. @Override
    8. public void regist(User user) {
    9. userDao.saveUser(user);
    10. }
    11. @Override
    12. public boolean existsUsername(String username) {
    13. return userDao.queryUserByUsername(username) != null;
    14. }
    15. }

    UserServiceTest类测试:

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

    7. 编写 web 层

    7.1 实现用户注册的功能

    修改 regist.html 和 regist_success.html 页面
    1、添加 base 标签
            
            <base href="http://localhost:8080/book/">
    2、修改 base 标签对页面中所有相对路径的影响(浏览器 F12,哪个报红,改哪个)
    以下是几个修改的示例:
            <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、修改注册表单的提交地址和请求方式

    需求:

    1)访问注册页面
    2)填写注册信息,提交给服务器
    3)服务器应该保存用户
    4)当用户已经存在----提示用户注册 失败,用户名已存在
    5)当用户不存在-----注册成功

    分析:

    1.在web包中编写RegistServlet类 并继承 HttpServlet
    2、获取请求的参数
    3、检查 验证码是否正确 
            正确
                    4、检查 用户名是否可用
                            可用
                                    调用 Service 保存到数据库
                            不可用
                                    跳回注册页面
            不正确
                    跳回注册页面

    代码:

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

    xml代码略

    7.2 用户登录功能的实现

    修改 login.html 页面和 login_success.html 页面
    1、添加 base 标签
            
            <base href="http://localhost:8080/book/">
    2、修改 base 标签对页面中所有相对路径的影响(浏览器 F12,哪个报红,改哪个)
    以下是几个修改的示例:
            <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、修改 login.html 表单的提交地址和请求方式 需求如下:
    需求:
            1)访问登陆页面
            2)填写用户名密码后提交
            3)服务器判断用户是否存在
            4)如果登陆失败 --->>>> 返回用户名或者密码错误信息
            5)如果登录成功 --->>>> 返回登陆成功 信息

    分析:

    1.  在web包中编写 LoginServlet 类 并继承 HttpServlet
    2、获取请求的参数
    3、调用 userService.login()登录处理业务(检查用户名密码是否正确)
            正确
                   跳到成功页面 login_success.html
            不正确
                    跳回登录页面
    代码:
    1. public class LoginServlet extends HttpServlet {
    2. private UserService userService = new UserServiceImpl();
    3. @Override
    4. protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    5. // 获取请求的参数
    6. String username = request.getParameter("username");
    7. String password = request.getParameter("password");
    8. // 调用 userService.login()登录处理业务
    9. User loginUser = userService.login(new User(null,username, password,null));
    10. if (loginUser == null) {
    11. // 不正确 跳回登录页面
    12. request.getRequestDispatcher("/pages/user/login.html").forward(request, response);
    13. } else {
    14. // 正确 跳转到登录成功页面
    15. request.getRequestDispatcher("/pages/user/login_success.html").forward(request, response);
    16. }
    17. }
    18. }

    书城第三阶段 -- 页面动态话,代码优化

    1. 页面 jsp 动态化

            1、在 html 页面顶行添加 page 指令。
            2、修改文件后缀名为:.jsp
            3、使用 IDEA 搜索替换.html .jsp(快捷键:Ctrl+Shift+R)

    2. 抽取页面中相同的内容

    2.1 head 中 css、jquery、base 标签

    1. <%
    2. String basePath = request.getScheme() + "://" +
    3. request.getServerName() + ":" +
    4. request.getServerPort() +
    5. request.getContextPath() + "/";
    6. String basePath2 = request.getScheme() + "://" +
    7. request.getServerName() + ":" +
    8. request.getServerPort() +
    9. request.getContextPath() + "/";
    10. %>
    11. <html>
    12. <head>
    13. <title>Titletitle>
    14. <base href="<%=basePath%>">
    15. <link type="text/css" rel="stylesheet" href="static/css/style.css">
    16. <script type="text/javascript" src="static/js/script/jquery-1.7.2.min.js">script>
    17. head>

    2.2 每个页面的页脚

    1. <body>
    2. <div id="bottom">
    3. <span>
    4. 尚硅谷书城.Copyright ©2015
    5. span>
    6. div>
    7. body>

    2.3 登录成功后的菜单

    1. <div>
    2. <span>欢迎<span class="um_span">韩总span>光临尚硅谷书城span>
    3. <a href="pages/order/order.jsp">我的订单a>
    4. <a href="index.jsp">注销a>  
    5. <a href="index.jsp">返回a>
    6. div>

    2.4 manager 模块的菜单

    1. <div>
    2. <a href="pages/manager/book_manager.jsp">图书管理a>
    3. <a href="pages/manager/order_manager.jsp">订单管理a>
    4. <a href="index.jsp">返回商城a>
    5. div>

    3. 登录,注册错误提示,及表单回显

    以登录回显为示例:
    Servlet 程序端需要添加回显信息到 Request 域中

     表单要回显信息:

    4. BaseServlet 的抽取

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

    4.1 代码优化1:合并 LoginServlet 和 RegistServlet 程序为 UserServlet 程序

     第一步:在注册和登录界面中编写隐藏域并修改请求地址

    给 login.jsp 添加隐藏域和修改请求地址

    给 tegist.jsp 页面添加隐藏域 action,和修改请求地址

    第二步:创建UserServlet类,并将LoginServlet类与RegistSerlet类里的代码复制进去

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

    4.2 优化代码2:使用反射优化大量 else if 代码

    1. protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    2. String action = request.getParameter("action");
    3. // 获取 action 业务鉴别字符串,获取相应的业务 方法反射对象
    4. try {
    5. Method method = this.getClass().getDeclaredMethod(action, HttpServletRequest.class, HttpServletResponse.class);
    6. // 调用目标业务 方法
    7. method.invoke(this, request, response);
    8. } catch (Exception e) {
    9. e.printStackTrace();
    10. }
    11. }

    4.3 代码优化3:抽取 BaseServlet 程序。

     创建BaseServlet抽象类,并继承UserServlet类等,将子类的doPost写到父类中,使其子类可以直接调用,不用再写一遍

    1. @WebServlet(name = "BaseServlet", value = "/BaseServlet")
    2. public abstract class BaseServlet extends HttpServlet {
    3. private UserService userService = new UserServiceImpl();
    4. @Override
    5. protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    6. String action = request.getParameter("action");
    7. // 获取 action 业务鉴别字符串,获取相应的业务 方法反射对象
    8. try {
    9. Method method = this.getClass().getDeclaredMethod(action, HttpServletRequest.class, HttpServletResponse.class);
    10. // 调用目标业务 方法
    11. method.invoke(this, request, response);
    12. } catch (Exception e) {
    13. e.printStackTrace();
    14. }
    15. }
    16. }
    修改 UserServlet 程序继承 BaseServlet 程序。

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

            BeanUtils 工具类,它可以一次性的把所有请求的参数注入到 JavaBean 中。
            BeanUtils 工具类,经常用于把 Map 中的值注入到 JavaBean 中,或者是对象属性值的拷贝操作。
            BeanUtils 它不是 Jdk 的类。而是第三方的工具类。所以需要导包。
                    1、导入需要的 jar 包:
                            commons-beanutils-1.8.0.jar
                            commons-logging-1.1.1.jar
                    2、编写 WebUtils 工具类使用:
    WebUtils 工具类:
    1. public class WebUtils {
    2. public static T copyParamToBean(Map value, T bean) {
    3. try {
    4. // 把所有请求的参数都注入到 user 对象中
    5. BeanUtils.populate(bean,value);
    6. } catch (Exception e) {
    7. e.printStackTrace();
    8. }
    9. return bean;
    10. }
    11. }

    6. 使用 EL 表达式修改表单回显

    以登录为示例:

    书城第四阶段

    1. 图书模块

    1.1 编写图书模块的数据库表

    1. CREATE TABLE t_book(
    2. `id` INT PRIMARY KEY AUTO_INCREMENT,
    3. `name` VARCHAR(100),
    4. `price` DECIMAL(11,2),
    5. `author` VARCHAR(100),
    6. `sales` INT,
    7. `stock` INT,
    8. `img_path` VARCHAR(200)
    9. );

    测试表:

    1. ## 插入初始化测试数据
    2. insert into t_book(`id` , `name` , `author` , `price` , `sales` , `stock` , `img_path`)
    3. values(null , 'java从入门到放弃' , '国哥' , 80 , 9999 , 9 , 'static/img/default.jpg');
    4. insert into t_book(`id` , `name` , `author` , `price` , `sales` , `stock` , `img_path`)
    5. values(null , '数据结构与算法' , '严敏君' , 78.5 , 6 , 13 , 'static/img/default.jpg');
    6. insert into t_book(`id` , `name` , `author` , `price` , `sales` , `stock` , `img_path`)
    7. values(null , '怎样拐跑别人的媳妇' , '龙伍' , 68, 99999 , 52 , 'static/img/default.jpg');
    8. insert into t_book(`id` , `name` , `author` , `price` , `sales` , `stock` , `img_path`)
    9. values(null , '木虚肉盖饭' , '小胖' , 16, 1000 , 50 , 'static/img/default.jpg');
    10. insert into t_book(`id` , `name` , `author` , `price` , `sales` , `stock` , `img_path`)
    11. values(null , 'C++编程思想' , '刚哥' , 45.5 , 14 , 95 , 'static/img/default.jpg');
    12. insert into t_book(`id` , `name` , `author` , `price` , `sales` , `stock` , `img_path`)
    13. values(null , '蛋炒饭' , '周星星' , 9.9, 12 , 53 , 'static/img/default.jpg');
    14. insert into t_book(`id` , `name` , `author` , `price` , `sales` , `stock` , `img_path`)
    15. values(null , '赌神' , '龙伍' , 66.5, 125 , 535 , 'static/img/default.jpg');
    16. insert into t_book(`id` , `name` , `author` , `price` , `sales` , `stock` , `img_path`)
    17. values(null , 'Java编程思想' , '阳哥' , 99.5 , 47 , 36 , 'static/img/default.jpg');
    18. insert into t_book(`id` , `name` , `author` , `price` , `sales` , `stock` , `img_path`)
    19. values(null , 'JavaScript从入门到精通' , '婷姐' , 9.9 , 85 , 95 , 'static/img/default.jpg');
    20. insert into t_book(`id` , `name` , `author` , `price` , `sales` , `stock` , `img_path`)
    21. values(null , 'cocos2d-x游戏编程入门' , '国哥' , 49, 52 , 62 , 'static/img/default.jpg');
    22. insert into t_book(`id` , `name` , `author` , `price` , `sales` , `stock` , `img_path`)
    23. values(null , 'C语言程序设计' , '谭浩强' , 28 , 52 , 74 , 'static/img/default.jpg');
    24. insert into t_book(`id` , `name` , `author` , `price` , `sales` , `stock` , `img_path`)
    25. values(null , 'Lua语言程序设计' , '雷丰阳' , 51.5 , 48 , 82 , 'static/img/default.jpg');
    26. insert into t_book(`id` , `name` , `author` , `price` , `sales` , `stock` , `img_path`)
    27. values(null , '西游记' , '罗贯中' , 12, 19 , 9999 , 'static/img/default.jpg');
    28. insert into t_book(`id` , `name` , `author` , `price` , `sales` , `stock` , `img_path`)
    29. values(null , '水浒传' , '华仔' , 33.05 , 22 , 88 , 'static/img/default.jpg');
    30. insert into t_book(`id` , `name` , `author` , `price` , `sales` , `stock` , `img_path`)
    31. values(null , '操作系统原理' , '刘优' , 133.05 , 122 , 188 , 'static/img/default.jpg');
    32. insert into t_book(`id` , `name` , `author` , `price` , `sales` , `stock` , `img_path`)
    33. values(null , '数据结构 java版' , '封大神' , 173.15 , 21 , 81 , 'static/img/default.jpg');
    34. insert into t_book(`id` , `name` , `author` , `price` , `sales` , `stock` , `img_path`)
    35. values(null , 'UNIX高级环境编程' , '乐天' , 99.15 , 210 , 810 , 'static/img/default.jpg');
    36. insert into t_book(`id` , `name` , `author` , `price` , `sales` , `stock` , `img_path`)
    37. values(null , 'javaScript高级编程' , '国哥' , 69.15 , 210 , 810 , 'static/img/default.jpg');
    38. insert into t_book(`id` , `name` , `author` , `price` , `sales` , `stock` , `img_path`)
    39. values(null , '大话设计模式' , '国哥' , 89.15 , 20 , 10 , 'static/img/default.jpg');
    40. insert into t_book(`id` , `name` , `author` , `price` , `sales` , `stock` , `img_path`)
    41. values(null , '人月神话' , '刚哥' , 88.15 , 20 , 80 , 'static/img/default.jpg');
    42. ## 查看表内容
    43. select id,name,author,price,sales,stock,img_path from t_book;

    1.2 编写图书模块的 JavaBean

    1. public class Book {
    2. private Integer id;
    3. private String name;
    4. private String author;
    5. private BigDecimal price;
    6. private Integer sales;
    7. private Integer stock;
    8. private String img_path = "static/img/default.jpg";
    9. public Book() {
    10. }
    11. public Book(Integer id, String name, String author, BigDecimal price, Integer sales, Integer stock, String img_path) {
    12. this.id = id;
    13. this.name = name;
    14. this.author = author;
    15. this.price = price;
    16. this.sales = sales;
    17. this.stock = stock;
    18. if (img_path != null && "".equals(img_path)) {
    19. this.img_path = img_path;
    20. }
    21. }
    22. public Integer getId() {
    23. return id;
    24. }
    25. public void setId(Integer id) {
    26. this.id = id;
    27. }
    28. public String getName() {
    29. return name;
    30. }
    31. public void setName(String name) {
    32. this.name = name;
    33. }
    34. public String getAuthor() {
    35. return author;
    36. }
    37. public void setAuthor(String author) {
    38. this.author = author;
    39. }
    40. public BigDecimal getPrice() {
    41. return price;
    42. }
    43. public void setPrice(BigDecimal price) {
    44. this.price = price;
    45. }
    46. public Integer getSales() {
    47. return sales;
    48. }
    49. public void setSales(Integer sales) {
    50. this.sales = sales;
    51. }
    52. public Integer getStock() {
    53. return stock;
    54. }
    55. public void setStock(Integer stock) {
    56. this.stock = stock;
    57. }
    58. public String getImg_path() {
    59. return img_path;
    60. }
    61. public void setImg_path(String img_path) {
    62. if (img_path != null && "".equals(img_path)) {
    63. this.img_path = img_path;
    64. }
    65. }
    66. @Override
    67. public String toString() {
    68. return "Book{" +
    69. "id=" + id +
    70. ", name='" + name + '\'' +
    71. ", author='" + author + '\'' +
    72. ", price=" + price +
    73. ", sales=" + sales +
    74. ", stock=" + stock +
    75. ", img_path='" + img_path + '\'' +
    76. '}';
    77. }
    78. }

    1.3、编写图书模块的 Dao 和测试 Dao

    BookDao接口:
    1. public interface BookDao {
    2. int addBook();
    3. int deleteBook();
    4. int update();
    5. Book queryBookById();
    6. List queryBooks();
    7. }

    BookDaoImpl实现类:

    1. public class BookDaoImpl extends BaseDao implements BookDao {
    2. @Override
    3. public int addBook(Book book) {
    4. String sql = "insert into t_book(`name`,`author`,`price`,`sales`,`stock`,`img_path`) values(?,?,?,?,?,?)";
    5. return update(sql, book.getName(), book.getAuthor(), book.getPrice(),
    6. book.getSales(), book.getStock(), book.getImg_path());
    7. }
    8. @Override
    9. public int deleteBookById(Integer id) {
    10. String sql = "delete from t_book where id = ?";
    11. return update(sql,id);
    12. }
    13. @Override
    14. public int updateBook(Book book) {
    15. String sql = "update t_book set `name` = ?,`author` = ?,`price` = ?,`sales` = ?,`stock` = ?,`img_path` = ? where id = ?";
    16. return update(sql, book.getName(), book.getAuthor(), book.getPrice(),
    17. book.getSales(), book.getStock(), book.getImg_path(),book.getId());
    18. }
    19. @Override
    20. public Book queryBookById(Integer id) {
    21. String sql = "select `id`,`name`,`author`,`price`,`sales`,`stock`,`img_path` from t_book where id = ?";
    22. return queryForOne(Book.class,sql,id);
    23. }
    24. @Override
    25. public List queryBooks() {
    26. String sql = "select `id`,`name`,`author`,`price`,`sales`,`stock`,`img_path` from t_book";
    27. return queryForList(Book.class,sql);
    28. }
    29. }

    测试:

    1. public class BookDaoTest {
    2. private BookDao bookDao = new BookDaoImpl();
    3. @Test
    4. public void addBook() {
    5. bookDao.addBook(new Book(null,"强哥好帅","chenyixin",new BigDecimal(123),999,999,null));
    6. System.out.println("添加成功");
    7. }
    8. @Test
    9. public void deleteBookById() {
    10. bookDao.deleteBookById(21);
    11. }
    12. @Test
    13. public void updateBook() {
    14. bookDao.updateBook(new Book(21, "大家都好帅", "佚名", new BigDecimal(123), 999, 999, null));
    15. }
    16. @Test
    17. public void queryBookById() {
    18. System.out.println(bookDao.queryBookById(21));
    19. }
    20. @Test
    21. public void queryBooks() {
    22. for (Book queryBook : bookDao.queryBooks()) {
    23. System.out.println(queryBook);
    24. }
    25. }
    26. }

    1.4、编写图书模块的 Service 和测试 Service

    BookService 接口:

    1. public interface BookService {
    2. public void addBook(Book book);
    3. public void delete(Integer id);
    4. public void update(Book book);
    5. public Book queryBookById(Integer id);
    6. public List queryBooks();
    7. }

    BookServiceImpl 实现类:

    1. public class BookServiceImpl implements BookService {
    2. private BookDao bookDao = new BookDaoImpl();
    3. @Override
    4. public void addBook(Book book) {
    5. bookDao.addBook(book);
    6. }
    7. @Override
    8. public void delete(Integer id) {
    9. bookDao.deleteBookById(id);
    10. }
    11. @Override
    12. public void update(Book book) {
    13. bookDao.updateBook(book);
    14. }
    15. @Override
    16. public Book queryBookById(Integer id) {
    17. return bookDao.queryBookById(id);
    18. }
    19. @Override
    20. public List queryBooks() {
    21. return bookDao.queryBooks();
    22. }
    23. }

    测试:

    1. public class BookServiceTest {
    2. private BookService bookService = new BookServiceImpl();
    3. @Test
    4. public void addBook() {
    5. bookService.addBook(new Book(null,"强哥好帅","chenyixin",new BigDecimal(123),999,999,null));
    6. System.out.println("修改成功");
    7. }
    8. @Test
    9. public void delete() {
    10. bookService.delete(22);
    11. }
    12. @Test
    13. public void update() {
    14. bookService.update(new Book(22, "大家都好帅", "佚名", new BigDecimal(123), 999, 999, null));
    15. }
    16. @Test
    17. public void queryBookById() {
    18. System.out.println( bookService.queryBookById(22));
    19. }
    20. @Test
    21. public void queryBooks() {
    22. for (Book queryBook : bookService.queryBooks()) {
    23. System.out.println(queryBook);
    24. }
    25. }
    26. }


    2. 编写图书模块的 Web 层

    前后台的简单介绍

    2.1 图书列表功能的实现

    图解列表功能流程:

    思路流程:

            1.在manager_menu.jsp页面中修改【图书管理】请求地址
            2. 在web包中创建BookServlet类,并添加list方法
            3.修改 pages/manager/book_manager.jsp 页面的数据遍历输出

    1.在manager_menu.jsp页面中修改【图书管理】请求地址

    action=list 表示调用list方法 (反射)

    2. 创建BookServlet 程序中,并添加 list 方法:

    1. @WebServlet(name = "BookServlet", value = "/manager/bookServlet")
    2. public class BookServlet extends BaseServlet {
    3. private BookService bookService = new BookServiceImpl();
    4. protected void list(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    5. //1 通过 BookService 查询全部图书
    6. System.out.println("进来了");
    7. List books = bookService.queryBooks();
    8. //2 把全部图书保存到 Request 域中
    9. request.setAttribute("books", books);
    10. //3、请求转发到/pages/manager/book_manager.jsp 页面
    11. request.getRequestDispatcher("/pages/manager/book_manager.jsp").forward(request,response);
    12. }
    13. }

    注意:a标签是get请求,所以要在BaseSerlet中写doGet方法:

    1. protected void doGet(HttpServletRequest req, HttpServletResponse resp)
    2. throws ServletException, IOException {
    3. doPost(req, resp);
    4. }

    3.修改 pages/manager/book_manager.jsp 页面的数据遍历输出

    1. <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
    2. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    3. html>
    4. <html>
    5. <head>
    6. <meta charset="UTF-8">
    7. <title>图书管理title>
    8. <%@include file="/pages/common/head.jsp" %>
    9. head>
    10. <body>
    11. <div id="header">
    12. <img class="logo_img" alt="" src="static/img/logo.gif">
    13. <span class="wel_word">图书管理系统span>
    14. <%@include file="/pages/common/manager_menu.jsp" %>
    15. div>
    16. <div id="main">
    17. <table>
    18. <tr>
    19. <td>名称td>
    20. <td>价格td>
    21. <td>作者td>
    22. <td>销量td>
    23. <td>库存td>
    24. <td colspan="2">操作td>
    25. tr>
    26. <c:forEach items="${requestScope.books}" var="book">
    27. <tr>
    28. <td>${book.name}td>
    29. <td>${book.price}td>
    30. <td>${book.author}td>
    31. <td>${book.sales}td>
    32. <td>${book.stock}td>
    33. <td><a href="pages/manager/book_edit.jsp">修改a>td>
    34. <td><a href="#">删除a>td>
    35. tr>
    36. c:forEach>
    37. <tr>
    38. <td>td>
    39. <td>td>
    40. <td>td>
    41. <td>td>
    42. <td>td>
    43. <td>td>
    44. <td><a href="book_edit.jsp">添加图书a>td>
    45. tr>
    46. table>
    47. div>
    48. <%@include file="/pages/common/footer.jsp" %>
    49. body>
    50. html>

    2.2 添加图书功能的实现

     问题说明:表单重复提交:

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

    思路步骤:

            1.在book_edit.jsp 页面添加隐藏域并修改form标签的action属性

            2.在BookServlet中编写add方法

    1.在book_edit.jsp 页面添加隐藏域并修改form标签的action属性

     2.在BookServlet中编写add方法

    1. protected void add(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    2. // 1.获取请求的参数 封装成为Book对象
    3. Book book = WebUtils.copyParamToBean(request.getParameterMap(), new Book());
    4. // 2.调用BookServlet.addBook()保存图书
    5. bookService.addBook(book);
    6. // 3.使用重定向跳转到图书列表界面
    7. response.sendRedirect(request.getContextPath() + "/manager/bookServlet?action=list");
    8. }

    2.3 删除图书功能的实现

    图解删除流程:

    步骤:

            1. 修改删除的连接地址

            2. 编写BookServlet 程序中的 delete 方法

            3. 给删除添加确认提示操作

    1. 修改删除的连接地址

     2. 编写BookServlet 程序中的 delete 方法
    1. protected void delete(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    2. // 1.获取请求参数的id,图书编号
    3. String id = request.getParameter("id");
    4. int i = WebUtils.parseInt(id, 0);
    5. // 2.调用bookServlet.delete方法,删除图书
    6. bookService.delete(i);
    7. // 3.重定向回图书列表管理页面
    8. response.sendRedirect(request.getContextPath() + "/manager/bookServlet?action=list");
    9. }
    WebUtils 工具类添加转换 int 类型的工具方法
    1. public static int parseInt(String strId, int defaultValue) {
    2. try {
    3. return Integer.parseInt(strId);
    4. } catch (NumberFormatException e) {
    5. e.printStackTrace();
    6. }
    7. return defaultValue;
    8. }

    3. 给删除添加确认提示操作:

    2.4 修改图书功能的实现

    图解修改图书细节:(流程)

    1. 更新【修改】的请求地址:
    2. BookServlet 程序中添加 getBook 方法:
    1. protected void getBook(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    2. // 1.获取图书编号
    3. String id = request.getParameter("id");
    4. int i = WebUtils.parseInt(id, 0);
    5. // 2.条用BookServlet.queryBookById(id),得到要修改的图书信息(book对象)
    6. Book book = bookService.queryBookById(i);
    7. // 3.把图书保存到Request域中
    8. request.setAttribute("book", book);
    9. // 4.把请求妆发到/pages/manager/book_edit.jsp页面
    10. request.getRequestDispatcher("/pages/manager/book_edit.jsp").forward(request,response);
    11. }

    3. book_edit.jsp 页面中显示修改的数据

    1. <div id="main">
    2. <form action="manager/bookServlet">
    3. <input type="hidden" name="action" value="add"/>
    4. <table>
    5. <tr>
    6. <td>名称td>
    7. <td>价格td>
    8. <td>作者td>
    9. <td>销量td>
    10. <td>库存td>
    11. <td colspan="2">操作td>
    12. tr>
    13. <tr>
    14. <td><input name="name" type="text" value="${requestScope.book.name}"/>td>
    15. <td><input name="price" type="text" value="${requestScope.book.price}"/>td>
    16. <td><input name="author" type="text" value="${requestScope.book.author}"/>td>
    17. <td><input name="sales" type="text" value="${requestScope.book.sales}"/>td>
    18. <td><input name="stock" type="text" value="${requestScope.book.stock}"/>td>
    19. <td><input type="submit" value="提交"/>td>
    20. tr>
    21. table>
    22. form>
    23. div>
    4. 在 BookServlet 程序中添加 update 方法
    1. protected void update(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    2. // 1.获取请求参数,并封装成Book对象
    3. Book book = WebUtils.copyParamToBean(request.getParameterMap(), new Book());
    4. // 2.调用BookServlet.update(book)方法,修改图书
    5. bookService.update(book);
    6. // 3.重定向返回图书列表管理页面
    7. response.sendRedirect(request.getContextPath()+"/manager/bookServlet?action=list");
    8. }

    5. 解决 book_edit.jsp 页面,即要实现添加,又要实现修改操作。

    3. 图书分页

    3.1 分页模块的分析

    3.2 分页的初步实现

    步骤:

            1.修改manager_menu.jsp页面中 图书管理地址

            2.编写page类

            3.编写Bookservlet程序

            4. 编写BookService程序

            5. 编写BookDao程序

            6. 测试BookDao程序   

            7. 测试BookService程序

            8. 修改book_manager.jsp 页面

       

    1.修改manager_menu.jsp 页面中 图书管理地址
    2.编写page类
    1. /**
    2. * Page 是分页的模型对象
    3. * @param 是具体的模块的 javaBean 类
    4. */
    5. public class Page {
    6. public static final Integer PAGE_SIZE = 4;
    7. // 当前页码
    8. private Integer pageNo;
    9. // 总页码
    10. private Integer pageTotal;
    11. // 总记录数
    12. private Integer pateTotalCount;
    13. // 每页显示数量
    14. private Integer pateSize = PAGE_SIZE;
    15. //当前页数据
    16. private List items;
    3.编写Bookservlet程序

    1. protected void page(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    2. // 1.获取请求参数 pageNo 和 pageSize
    3. int pageNo = WebUtils.parseInt(request.getParameter("pageNo"), 1);
    4. int pageSize = WebUtils.parseInt(request.getParameter("pageSize"), Page.PAGE_SIZE);
    5. // 2.调用BookServlet.page(pageNo,pageSize),获得page对象
    6. Page page = bookService.page(pageNo, pageSize);
    7. // 3.将Page对象保存到Request域中
    8. request.setAttribute("page", page);
    9. // 4.请求转发到 /pages/manager/book_manager.jsp
    10. request.getRequestDispatcher("/pages/manager/book_manager.jsp").forward(request, response);
    11. }
    4. 编写BookService程序
    BookService接口中的page方法:
    Page page(int pageNo, int pageSize);

    BookServiceImpl实现类中的page方法:

    1. public Page page(int pageNo, int pageSize) {
    2. Page page = new Page<>();
    3. // 设置 当前页码
    4. page.setPageNo(pageNo);
    5. // 设置 当前每页显示数量
    6. page.setPateSize(pageSize);
    7. // 求总记录数
    8. Integer pageTotalCount = bookDao.queryForPageTotalCount();
    9. // 设置总记录数
    10. page.setPateTotalCount(pageTotalCount);
    11. // 求总页码
    12. Integer pageTotal = pageTotalCount / pageSize;
    13. if ((pageTotalCount % pageSize) > 0) {
    14. pageTotal++;
    15. }
    16. // 设置总页码
    17. page.setPageTotal(pageTotal);
    18. // 求当前页面数据
    19. // 求页面开始索引
    20. Integer begin = (pageNo - 1) * pageSize;
    21. List items = bookDao.queryForPageItems(begin, pageSize);
    22. // 设置当前页面数据
    23. page.setItems(items);
    24. return page;
    25. }

    5. 编写BookDao程序

    Bookdao接口:

    1. Integer queryForPageTotalCount();
    2. List queryForPageItems(Integer begin, int pageSize);

    BookdaoImpl实现类:

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

    6. 测试BookDao程序

    1. @Test
    2. public void queryForPageTotalCount() {
    3. System.out.println(bookDao.queryForPageTotalCount());
    4. }
    5. @Test
    6. public void queryForPageItems() {
    7. for (Book item : bookDao.queryForPageItems(8,4)) {
    8. System.out.println(item);
    9. }
    10. }

    7. 测试BookService程序

    1. @Test
    2. public void page() {
    3. System.out.println(bookService.page(1,4));
    4. }

    8. 修改book_manager.jsp 页面

    1. <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
    2. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    3. html>
    4. <html>
    5. <head>
    6. <meta charset="UTF-8">
    7. <title>图书管理title>
    8. <%@include file="/pages/common/head.jsp" %>
    9. head>
    10. <body>
    11. <div id="header">
    12. <img class="logo_img" alt="" src="static/img/logo.gif">
    13. <span class="wel_word">图书管理系统span>
    14. <%@include file="/pages/common/manager_menu.jsp" %>
    15. div>
    16. <div id="main">
    17. <table>
    18. <tr>
    19. <td>名称td>
    20. <td>价格td>
    21. <td>作者td>
    22. <td>销量td>
    23. <td>库存td>
    24. <td colspan="2">操作td>
    25. tr>
    26. <c:forEach items="${requestScope.page.items}" var="book">
    27. <tr>
    28. <td>${book.name}td>
    29. <td>${book.price}td>
    30. <td>${book.author}td>
    31. <td>${book.sales}td>
    32. <td>${book.stock}td>
    33. <td><a href="manager/bookServlet?action=getBook&id=${book.id}">修改a>td>
    34. <td><a class="deleteClass" href="manager/bookServlet?action=delete&id=${book.id}">删除a>td>
    35. tr>
    36. c:forEach>
    37. <tr>
    38. <td>td>
    39. <td>td>
    40. <td>td>
    41. <td>td>
    42. <td>td>
    43. <td>td>
    44. <td><a href="pages/manager/book_edit.jsp">添加图书a>td>
    45. tr>
    46. table>
    47. <div id="page_nav">
    48. <a href="#">首页a>
    49. <a href="#">上一页a>
    50. <a href="#">3a>
    51. 【${requestScope.page.pageNo}】
    52. <a href="#">5a>
    53. <a href="#">下一页a>
    54. <a href="#">末页a>
    55. 共${requestScope.page.pageTotal}页,${requestScope.page.pageTotalCount}条记录
    56. 到第<input value="4" name="pn" id="pn_input"/>
    57. <input type="button" value="确定">
    58. div>
    59. div>
    60. <%@include file="/pages/common/footer.jsp" %>
    61. body>
    62. html>

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

    1. <div id="page_nav">
    2. <%--大于首页,才显示--%>
    3. <c:if test="${requestScope.page.pageNo > 1}">
    4. <a href="manager/bookServlet?action=page&pageNo=1">首页a>
    5. <a href="manager/bookServlet?action=page&pageNo=${requestScope.page.pageNo - 1}">上一页a>
    6. c:if>
    7. <a href="#">3a>
    8. 【${requestScope.page.pageNo}】
    9. <a href="#">5a>
    10. <%-- 如果已经 是最后一页,则不显示下一页,末页 --%>
    11. <c:if test="${requestScope.page.pageNo < requestScope.page.pageTotal}">
    12. <a href="manager/bookServlet?action=page&pageNo=${requestScope.page.pageNo + 1}">下一页a>
    13. <a href="manager/bookServlet?action=page&pageNo=${requestScope.page.pageTotal}">末页a>
    14. c:if>
    15. 共${requestScope.page.pageTotal}页,${requestScope.page.pageTotalCount}条记录
    16. 到第<input value="4" name="pn" id="pn_input"/>
    17. <input type="button" value="确定">
    18. div>

    3.4 分页模块中跳转到指定页数功能实现

    1.对按钮绑定事件
    1. // 给按钮绑定点击事件
    2. $("#searchPageBtn").click(function () {
    3. var pageNo = $("#pn_input").val();
    4. // javaScript 语言中提供了一个 location 地址栏对象
    5. // 它有一个属性叫 href.它可以获取浏览器地址栏中的地址
    6. // href 属性可读,可写
    7. location.href = "${requestScope.basePath}manager/bookServlet?action=page&pageNo=" + pageNo;
    8. });

    2. 将标签中的bashPath路径存放到Request域中

    1. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    2. <%
    3. String basePath = request.getScheme() + "://" +
    4. request.getServerName() + ":" +
    5. request.getServerPort() +
    6. request.getContextPath() + "/";
    7. request.setAttribute("basePath",basePath);
    8. %>
    9. <html>
    10. <head>
    11. <title>Titletitle>
    12. <base href="<%=basePath%>">
    13. <link type="text/css" rel="stylesheet" href="static/css/style.css">
    14. <script type="text/javascript" src="static/js/script/jquery-1.7.2.min.js">script>
    15. head>

    3. BookService 中 page 方法中添加数据边界的有效检查:

    1. public Page page(int pageNo, int pageSize) {
    2. Page page = new Page<>();
    3. // 设置 当前每页显示数量
    4. page.setPageSize(pageSize);
    5. // 求总记录数
    6. Integer pageTotalCount = bookDao.queryForPageTotalCount();
    7. // 设置总记录数
    8. page.setPageTotalCount(pageTotalCount);
    9. // 求总页码
    10. Integer pageTotal = pageTotalCount / pageSize;
    11. if ((pageTotalCount % pageSize) > 0) {
    12. pageTotal++;
    13. }
    14. // 设置总页码
    15. page.setPageTotal(pageTotal);
    16. // 设置 当前页码
    17. /* 数据边界的有效检查 */
    18. if (pageNo < 1) {
    19. pageNo = 1;
    20. }
    21. if (pageNo > pageTotal) {
    22. pageNo = pageTotal;
    23. }
    24. page.setPageNo(pageNo);
    25. // 求当前页面数据
    26. // 求页面开始索引
    27. Integer begin = (pageNo - 1) * pageSize;
    28. List items = bookDao.queryForPageItems(begin, pageSize);
    29. // 设置当前页面数据
    30. page.setItems(items);
    31. return page;
    32. }

    3.5 分页模块中的页码显示

    需求:显示 5 个连续的页码,而且当前页码在中间。除了当前页码之外,每个页码都可以点击跳到指定页。
    分析
    情况 1 :如果总页码小于等于 5 的情况,页码的范围是: 1- 总页码
            1 页         1
            2 页         1,2
            3 页         1,2, 3
            4 页         1,2, 3 4
            5 页         1,2, 3 4 5
    情况 2 :总页码大于 5 的情况。假设一共 10
    小情况 1 :当前页码为前面 3 个: 1 2 3 的情况,页码范围是: 1-5.
            【1 2 3 4 5
                1【 2 3 4 5
                1,2 3 4 5
    小情况 2 :当前页码为最后 3 个, 8 9 10 ,页码范围是:总页码减 4 - 总页码
            6, 7 8 9 10
            6, 7 8 9 10
            6, 7 8 9 10
    小情况 3 4 5 6 7 ,页码范围是:当前页码减 2 - 当前页码加 2
            2, 3, 【4】 5 6
            3, 4 ,【 5】 6 7
            4, 5 ,【 6】 7 8
            5, 6 ,【 7】 8 9
    代码:
    1. <div id="page_nav">
    2. <%--大于首页,才显示--%>
    3. <c:if test="${requestScope.page.pageNo > 1}">
    4. <a href="manager/bookServlet?action=page&pageNo=1">首页a>
    5. <a href="manager/bookServlet?action=page&pageNo=${requestScope.page.pageNo - 1}">上一页a>
    6. c:if>
    7. <%--页码输出的开始--%>
    8. <c:choose>
    9. <%--情况 1:如果总页码小于等于 5 的情况,页码的范围是:1-总页码--%>
    10. <c:when test="${requestScope.page.pageTotal <= 5}">
    11. <c:set var="begin" value="1"/>
    12. <c:set var="end" value="${requestScope.page.pageTotal}"/>
    13. c:when>
    14. <%--情况 2:总页码大于 5 的情况--%>
    15. <c:when test="${requestScope.page.pageTotal > 5}">
    16. <c:choose>
    17. <%--小情况 1:当前页码为前面 3 个:1,2,3 的情况,页码范围是:1-5.--%>
    18. <c:when test="${requestScope.page.pageNo <= 3}">
    19. <c:set var="begin" value="1"/>
    20. <c:set var="end" value="5"/>
    21. c:when>
    22. <%--小情况 2:当前页码为最后 3 个,8,9,10,页码范围是:总页码减 4 - 总页码--%>
    23. <c:when test="${requestScope.page.pageNo > requestScope.page.pageTotal-3}">
    24. <c:set var="begin" value="${requestScope.page.pageTotal - 4}"/>
    25. <c:set var="end" value="${requestScope.page.pageTotal}"/>
    26. c:when>
    27. <%--小情况 3:4,5,6,7,页码范围是:当前页码减 2 - 当前页码加 2--%>
    28. <c:otherwise>
    29. <c:set var="begin" value="${requestScope.page.pageNo - 2}"/>
    30. <c:set var="end" value="${requestScope.page.pageNo + 2}"/>
    31. c:otherwise>
    32. c:choose>
    33. c:when>
    34. c:choose>
    35. <c:forEach begin="${begin}" end="${end}" var="i">
    36. <c:if test="${requestScope.page.pageNo == i}">
    37. 【${i}】
    38. c:if>
    39. <c:if test="${requestScope.page.pageNo != i}">
    40. <a href="manager/bookServlet?action=page&pageNo=${i}">${i}a>
    41. c:if>
    42. c:forEach>
    43. <%--页码输出的结束--%>
    44. <%-- 如果已经 是最后一页,则不显示下一页,末页 --%>
    45. <c:if test="${requestScope.page.pageNo < requestScope.page.pageTotal}">
    46. <a href="manager/bookServlet?action=page&pageNo=${requestScope.page.pageNo + 1}">下一页a>
    47. <a href="manager/bookServlet?action=page&pageNo=${requestScope.page.pageTotal}">末页a>
    48. c:if>
    49. 共${requestScope.page.pageTotal}页,${requestScope.page.pageTotalCount}条记录
    50. 到第<input value="${requestScope.page.pageNo}" name="pn" id="pn_input"/>
    51. <input id="searchPageBtn" type="button" value="确定">
    52. div>

    3.6 修改分页后,增加,删除,修改图书信息的回显页面

    以修改图书为示例:
    1、在修改的请求地址上追加当前页码参数:

    2、在 book_edit.jsp 页面中使用隐藏域记录下 pageNo 参数

     3、在服务器重定向的时候,获取当前页码追加上进行跳转

    1. protected void update(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    2. // 1.获取请求参数,并封装成Book对象
    3. Book book = WebUtils.copyParamToBean(request.getParameterMap(), new Book());
    4. // 2.调用BookServlet.update(book)方法,修改图书
    5. bookService.update(book);
    6. // 3.重定向返回图书列表管理页面
    7. response.sendRedirect(request.getContextPath() + "/manager/bookServlet?action=page&pageNo=" + request.getParameter("pageNo"));
    8. }

    4.首页 index.jsp 的跳转

    4.1 思路图解

    步骤: 

            1.复制以分index到pages/client中

            2.编写ClientBookServlet程序,并继承BaseServlet父类

            3.将原来的index.jsp内容全删,改成去求转发

            4.修改复制后的index

    4.2 代码实现

    1.复制以分index到pages/client中

      2.编写ClientBookServlet程序,并继承BaseServlet父类

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

    3. 将原来的index.jsp内容全删,改成去求转发

    1. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    2. <jsp:forward page="/client/bookServlet?action=page">jsp:forward>

    4.修改复制后的index

    1. <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
    2. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    3. html>
    4. <html>
    5. <head>
    6. <meta charset="UTF-8">
    7. <title>书城首页title>
    8. <%@include file="/pages/common/head.jsp"%>
    9. head>
    10. <body>
    11. <div id="header">
    12. <img class="logo_img" alt="" src="static/img/logo.gif">
    13. <span class="wel_word">网上书城span>
    14. <div>
    15. <a href="pages/user/login.jsp">登录a> |
    16. <a href="pages/user/regist.jsp">注册a>   
    17. <a href="pages/cart/cart.jsp">购物车a>
    18. <a href="pages/manager/manager.jsp">后台管理a>
    19. div>
    20. div>
    21. <div id="main">
    22. <div id="book">
    23. <div class="book_cond">
    24. <form action="" method="get">
    25. 价格:<input id="min" type="text" name="min" value=""> 元 -
    26. <input id="max" type="text" name="max" value="">
    27. <input type="submit" value="查询"/>
    28. form>
    29. div>
    30. <div style="text-align: center">
    31. <span>您的购物车中有3件商品span>
    32. <div>
    33. 您刚刚将<span style="color: red">时间简史span>加入到了购物车中
    34. div>
    35. div>
    36. <%-- 书籍的开始 --%>
    37. <c:forEach items="${requestScope.page.items}" var="book">
    38. <div class="b_list">
    39. <div class="img_div">
    40. <img class="book_img" alt="" src="${book.img_path}"/>
    41. div>
    42. <div class="book_info">
    43. <div class="book_name">
    44. <span class="sp1">书名:span>
    45. <span class="sp2">${book.name}span>
    46. div>
    47. <div class="book_author">
    48. <span class="sp1">作者:span>
    49. <span class="sp2">${book.author}span>
    50. div>
    51. <div class="book_price">
    52. <span class="sp1">价格:span>
    53. <span class="sp2">¥${book.price}span>
    54. div>
    55. <div class="book_sales">
    56. <span class="sp1">销量:span>
    57. <span class="sp2">${book.sales}span>
    58. div>
    59. <div class="book_amount">
    60. <span class="sp1">库存:span>
    61. <span class="sp2">${book.stock}span>
    62. div>
    63. <div class="book_add">
    64. <button>加入购物车button>
    65. div>
    66. div>
    67. div>
    68. c:forEach>
    69. <%-- 书籍的结束 --%>
    70. div>
    71. <%-- 分页条的开始 --%>
    72. <div id="page_nav">
    73. <%--大于首页,才显示--%>
    74. <c:if test="${requestScope.page.pageNo > 1}">
    75. <a href="client/bookServlet?action=page&pageNo=1">首页a>
    76. <a href="client/bookServlet?action=page&pageNo=${requestScope.page.pageNo - 1}">上一页a>
    77. c:if>
    78. <%--页码输出的开始--%>
    79. <c:choose>
    80. <%--情况 1:如果总页码小于等于 5 的情况,页码的范围是:1-总页码--%>
    81. <c:when test="${requestScope.page.pageTotal <= 5}">
    82. <c:set var="begin" value="1"/>
    83. <c:set var="end" value="${requestScope.page.pageTotal}"/>
    84. c:when>
    85. <%--情况 2:总页码大于 5 的情况--%>
    86. <c:when test="${requestScope.page.pageTotal > 5}">
    87. <c:choose>
    88. <%--小情况 1:当前页码为前面 3 个:1,2,3 的情况,页码范围是:1-5.--%>
    89. <c:when test="${requestScope.page.pageNo <= 3}">
    90. <c:set var="begin" value="1"/>
    91. <c:set var="end" value="5"/>
    92. c:when>
    93. <%--小情况 2:当前页码为最后 3 个,8,9,10,页码范围是:总页码减 4 - 总页码--%>
    94. <c:when test="${requestScope.page.pageNo > requestScope.page.pageTotal-3}">
    95. <c:set var="begin" value="${requestScope.page.pageTotal - 4}"/>
    96. <c:set var="end" value="${requestScope.page.pageTotal}"/>
    97. c:when>
    98. <%--小情况 3:4,5,6,7,页码范围是:当前页码减 2 - 当前页码加 2--%>
    99. <c:otherwise>
    100. <c:set var="begin" value="${requestScope.page.pageNo - 2}"/>
    101. <c:set var="end" value="${requestScope.page.pageNo + 2}"/>
    102. c:otherwise>
    103. c:choose>
    104. c:when>
    105. c:choose>
    106. <c:forEach begin="${begin}" end="${end}" var="i">
    107. <c:if test="${requestScope.page.pageNo == i}">
    108. 【${i}】
    109. c:if>
    110. <c:if test="${requestScope.page.pageNo != i}">
    111. <a href="client/bookServlet?action=page&pageNo=${i}">${i}a>
    112. c:if>
    113. c:forEach>
    114. <%--页码输出的结束--%>
    115. <%-- 如果已经 是最后一页,则不显示下一页,末页 --%>
    116. <c:if test="${requestScope.page.pageNo < requestScope.page.pageTotal}">
    117. <a href="client/bookServlet?action=page&pageNo=${requestScope.page.pageNo + 1}">下一页a>
    118. <a href="client/bookServlet?action=page&pageNo=${requestScope.page.pageTotal}">末页a>
    119. c:if>
    120. 共${requestScope.page.pageTotal}页,${requestScope.page.pageTotalCount}条记录
    121. 到第<input value="${requestScope.page.pageNo}" name="pn" id="pn_input"/>
    122. <input id="searchPageBtn" type="button" value="确定">
    123. div>
    124. <script type="text/javascript">
    125. $(function (){
    126. // 给按钮绑定点击事件
    127. $("#searchPageBtn").click(function () {
    128. var pageNo = $("#pn_input").val();
    129. // javaScript 语言中提供了一个 location 地址栏对象
    130. // 它有一个属性叫 href.它可以获取浏览器地址栏中的地址
    131. // href 属性可读,可写
    132. location.href = "${requestScope.basePath}manager/bookServlet?action=page&pageNo=" + pageNo;
    133. });
    134. });
    135. script>
    136. <%-- 分页条的结束 --%>
    137. div>
    138. <%@include file="/pages/common/footer.jsp"%>
    139. body>
    140. html>

    4.3 抽取分页条

    步骤:

            1.page 对象中添加 url 属性

            2.在 Servlet 程序的 page 分页方法中设置 url 的分页请求地址

            3.修改分页条中请求地址为 url 变量输出,并抽取一个单独的 jsp 页面

    1. page 对象中添加 url 属性

     2.在 Servlet 程序的 page 分页方法中设置 url 的分页请求地址

    在BookServlet类中:

     在ClientBookServlet类中

     

    3.修改分页条中请求地址为 url 变量输出 , 并抽取一个单独的 jsp 页面
    1. <%--
    2. Created by IntelliJ IDEA.
    3. User: pc
    4. Date: 2022/7/28
    5. Time: 21:37
    6. To change this template use File | Settings | File Templates.
    7. --%>
    8. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    9. <%-- 分页条的开始 --%>
    10. <div id="page_nav">
    11. <%--大于首页,才显示--%>
    12. <c:if test="${requestScope.page.pageNo > 1}">
    13. <a href="${requestScope.page.url}&pageNo=1">首页a>
    14. <a href="${requestScope.page.url}&pageNo=${requestScope.page.pageNo - 1}">上一页a>
    15. c:if>
    16. <%--页码输出的开始--%>
    17. <c:choose>
    18. <%--情况 1:如果总页码小于等于 5 的情况,页码的范围是:1-总页码--%>
    19. <c:when test="${requestScope.page.pageTotal <= 5}">
    20. <c:set var="begin" value="1"/>
    21. <c:set var="end" value="${requestScope.page.pageTotal}"/>
    22. c:when>
    23. <%--情况 2:总页码大于 5 的情况--%>
    24. <c:when test="${requestScope.page.pageTotal > 5}">
    25. <c:choose>
    26. <%--小情况 1:当前页码为前面 3 个:1,2,3 的情况,页码范围是:1-5.--%>
    27. <c:when test="${requestScope.page.pageNo <= 3}">
    28. <c:set var="begin" value="1"/>
    29. <c:set var="end" value="5"/>
    30. c:when>
    31. <%--小情况 2:当前页码为最后 3 个,8,9,10,页码范围是:总页码减 4 - 总页码--%>
    32. <c:when test="${requestScope.page.pageNo > requestScope.page.pageTotal-3}">
    33. <c:set var="begin" value="${requestScope.page.pageTotal - 4}"/>
    34. <c:set var="end" value="${requestScope.page.pageTotal}"/>
    35. c:when>
    36. <%--小情况 3:4,5,6,7,页码范围是:当前页码减 2 - 当前页码加 2--%>
    37. <c:otherwise>
    38. <c:set var="begin" value="${requestScope.page.pageNo - 2}"/>
    39. <c:set var="end" value="${requestScope.page.pageNo + 2}"/>
    40. c:otherwise>
    41. c:choose>
    42. c:when>
    43. c:choose>
    44. <c:forEach begin="${begin}" end="${end}" var="i">
    45. <c:if test="${requestScope.page.pageNo == i}">
    46. 【${i}】
    47. c:if>
    48. <c:if test="${requestScope.page.pageNo != i}">
    49. <a href="${requestScope.page.url}&pageNo=${i}">${i}a>
    50. c:if>
    51. c:forEach>
    52. <%--页码输出的结束--%>
    53. <%-- 如果已经 是最后一页,则不显示下一页,末页 --%>
    54. <c:if test="${requestScope.page.pageNo < requestScope.page.pageTotal}">
    55. <a href="${requestScope.page.url}&pageNo=${requestScope.page.pageNo + 1}">下一页a>
    56. <a href="${requestScope.page.url}&pageNo=${requestScope.page.pageTotal}">末页a>
    57. c:if>
    58. 共${requestScope.page.pageTotal}页,${requestScope.page.pageTotalCount}条记录
    59. 到第<input value="${requestScope.page.pageNo}" name="pn" id="pn_input"/>
    60. <input id="searchPageBtn" type="button" value="确定">
    61. div>
    62. <script type="text/javascript">
    63. $(function (){
    64. // 给按钮绑定点击事件
    65. $("#searchPageBtn").click(function () {
    66. var pageNo = $("#pn_input").val();
    67. // javaScript 语言中提供了一个 location 地址栏对象
    68. // 它有一个属性叫 href.它可以获取浏览器地址栏中的地址
    69. // href 属性可读,可写
    70. location.href = "${requestScope.basePath}${requestScope.page.url}&pageNo=" + pageNo;
    71. });
    72. });
    73. script>
    74. <%-- 分页条的结束 --%>

    5. 首页价格搜索

    思路流程图

    1.修改表单的发送地址,接添加隐藏域 ,并优化部分代码

     2.在ClientBookServlet程序中编写pageByPrice方法

    1. protected void pageByPrice(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    2. System.out.println("经过了前台");
    3. // 1.获取请求参数 pageNo 和 pageSize
    4. int pageNo = WebUtils.parseInt(request.getParameter("pageNo"), 1);
    5. int pageSize = WebUtils.parseInt(request.getParameter("pageSize"), Page.PAGE_SIZE);
    6. int min = WebUtils.parseInt(request.getParameter("min"), 0);
    7. int max = WebUtils.parseInt(request.getParameter("max"), Integer.MAX_VALUE);
    8. // 2.调用BookServlet.page(pageNo,pageSize),获得page对象
    9. Page page = bookService.pageByPrice(pageNo, pageSize,min,max);
    10. StringBuilder sb = new StringBuilder("client/bookServlet?action=pageByPrice");
    11. if (request.getParameter("min") != null) {
    12. sb.append("&min=").append(request.getParameter("min"));
    13. }
    14. if (request.getParameter("min") != null) {
    15. sb.append("&max=").append(request.getParameter("max"));
    16. }
    17. page.setUrl(sb.toString());
    18. // 3.将Page对象保存到Request域中
    19. request.setAttribute("page", page);
    20. // 4.请求转发到 /pages/client/index.js
    21. request.getRequestDispatcher("/pages/client/index.jsp").forward(request, response);
    22. }

    3.编写BookServlet程序

    1. public Page pageByPrice(int pageNo, int pageSize, int min, int max) {
    2. Page page = new Page<>();
    3. // 设置 当前每页显示数量
    4. page.setPageSize(pageSize);
    5. // 求总记录数
    6. Integer pageTotalCount = bookDao.queryForPageTotalCountByPrice(min,max);
    7. // 设置总记录数
    8. page.setPageTotalCount(pageTotalCount);
    9. // 求总页码
    10. Integer pageTotal = pageTotalCount / pageSize;
    11. if ((pageTotalCount % pageSize) > 0) {
    12. pageTotal++;
    13. }
    14. // 设置总页码
    15. page.setPageTotal(pageTotal);
    16. // 设置 当前页码
    17. /* 数据边界的有效检查 */
    18. if (pageNo < 1) {
    19. pageNo = 1;
    20. }
    21. if (pageNo > pageTotal) {
    22. pageNo = pageTotal;
    23. }
    24. page.setPageNo(pageNo);
    25. // 求当前页面数据
    26. // 求页面开始索引
    27. Integer begin = (pageNo - 1) * pageSize;
    28. List items = bookDao.queryForPageItemsByPrice(begin, pageSize,min,max);
    29. // 设置当前页面数据
    30. page.setItems(items);
    31. return page;
    32. }

    4.编写Bookdao程序

    1. @Override
    2. public Integer queryForPageTotalCountByPrice(int min, int max) {
    3. String sql = "select count(*) from t_book where price between ? and ?";
    4. Number number = (Number) queryForSingleValue(sql, min, max);
    5. return number.intValue();
    6. }
    7. @Override
    8. public List queryForPageItemsByPrice(Integer begin, int pageSize, int min, int max) {
    9. String sql = "select `id`,`name`,`author`,`price`,`sales`,`stock`,`img_path` " +
    10. "from t_book where price between ? and ? order by price asc limit ?,?";
    11. return queryForList(Book.class, sql, min, max, begin, pageSize);
    12. }

    5.测试Bookdao程序

    1. @Test
    2. public void queryForPageTotalCountByPrice() {
    3. System.out.println(bookDao.queryForPageTotalCountByPrice(10,50));
    4. }
    5. @Test
    6. public void queryForPageItemsByPrice() {
    7. for (Book item : bookDao.queryForPageItemsByPrice(0,4,10,50)) {
    8. System.out.println(item);
    9. }
    10. }

    6.测试BookService程序

    1. @Test
    2. public void pageByPrice() {
    3. System.out.println(bookService.pageByPrice(1,4,10,50));
    4. }

    项目第五阶段 -- 完善登录/注册功能

    1. 登陆---显示用户名

    需求:在用户登录成功后显示用户名欢迎菜单

    步骤:
            1. UserServlet 程序中保存用户登录的信息
            2.修改 login_succuess_menu.jsp 
            3.还要修改首页 index.jsp 页面的菜单
            (没登陆时显示登录/注册,若已登录显示用户欢迎菜单)
    1.UserServlet 程序中保存用户登录的信息
    1. /**
    2. * 处理登录功能
    3. *
    4. * @param request
    5. * @param response
    6. * @throws ServletException
    7. * @throws IOException
    8. */
    9. protected void login(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    10. // 获取请求的参数
    11. User user = WebUtils.copyParamToBean(request.getParameterMap(), new User());
    12. // 调用 userService.login()登录处理业务
    13. User loginUser = userService.login(user);
    14. if (loginUser == null) {
    15. // 不正确
    16. // 把错误信息,和回显的表单项信息,保存到Request域中
    17. request.setAttribute("msg", "用户名或密码错误!");
    18. request.setAttribute("username", user.getUsername());
    19. // 跳回登录页面
    20. request.getRequestDispatcher("/pages/user/login.jsp").forward(request, response);
    21. } else {
    22. // 正确
    23. // 用户信息保存到Session对象中
    24. request.getSession().setAttribute("loginUser", loginUser);
    25. // 跳转到登录成功页面
    26. request.getRequestDispatcher("/pages/user/login_success.jsp").forward(request, response);
    27. }
    28. }

     2.修改 login_succuess_menu.jsp  

    3.还要修改首页 index.jsp 页面的菜单
    1. <div id="header">
    2. <img class="logo_img" alt="" src="static/img/logo.gif">
    3. <span class="wel_word">网上书城span>
    4. <div>
    5. <c:if test="${empty sessionScope.user}" >
    6. <a href="pages/user/login.jsp">登录a> |
    7. <a href="pages/user/regist.jsp">注册a>
    8. c:if>
    9. <c:if test="${not empty sessionScope.user}">
    10. <span>欢迎<span class="um_span">${sessionScope.user.username}span>光临尚硅谷书城span>
    11. <a href="pages/order/order.jsp">我的订单a>
    12. <a href="index.jsp">注销a>
    13. c:if>  
    14. <a href="pages/cart/cart.jsp">购物车a>
    15. <a href="pages/manager/manager.jsp">后台管理a>
    16. div>
    17. div>

    2. 登出---注销用户(即退出登录)

    步骤:
            1.UserServlet 程序中添加 logout 方法
                    1. 销毁 Session 中用户登录的信息(或者销毁 Session
                    2. 重定向到首页(或登录页面)。
            2.  修改【注销】的菜单地址
    1.UserServlet 程序中添加 logout 方法
    1. /**
    2. * 注销登录功能
    3. *
    4. * @param request
    5. * @param response
    6. * @throws ServletException
    7. * @throws IOException
    8. */
    9. protected void logout(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    10. // 1、销毁 Session 中用户登录的信息(或者销毁 Session)
    11. request.getSession().invalidate();
    12. // 2、重定向到首页
    13. response.sendRedirect(request.getContextPath());
    14. }

    2. 修改【注销】的菜单地址

    3. 表单重复提交之-----验证码

    表单重复提交有三种常见的情况:
            一:提交完表单。服务器使用请求转来进行页面跳转。这个时候,用户按下功能键 F5,就会发起最后一次的请求。 造成表单重复提交问题。解决方法:使用重定向来进行跳转
            二:用户正常提交服务器,但是由于网络延迟等原因,迟迟未收到服务器的响应,这个时候,用户以为提交失败,就会着急,然后多点了几次提交操作,也会造成表单重复提交。
            三:用户正常提交服务器。服务器也没有延迟,但是提交完成后,用户回退浏览器。重新提交。也会造成表单重复提交。

    4. 谷歌 kaptcha 图片验证码的使用

    谷歌验证码 kaptcha 使用步骤如下:
            1、导入谷歌验证码的 jar
                    kaptcha-2.3.2.jar
            2、在 web.xml 中去配置用于生成验证码的 Servlet 程序
            3、在表单中使用 img 标签去显示验证码图片并使用它
            4、在服务器获取谷歌生成的验证码和客户端发送过来的验证码比较使用。
    1、导入谷歌验证码的 jar

      2、在 web.xml 中去配置用于生成验证码的 Servlet 程序

    1. <servlet>
    2. <servlet-name>KaptchaServletservlet-name>
    3. <servlet-class>com.google.code.kaptcha.servlet.KaptchaServletservlet-class>
    4. servlet>
    5. <servlet-mapping>
    6. <servlet-name>KaptchaServletservlet-name>
    7. <url-pattern>/kaptcha.jpgurl-pattern>
    8. servlet-mapping>

     3、在表单中使用 img 标签去显示验证码图片并使用它

     4、在服务器获取谷歌生成的验证码和客户端发送过来的验证码比较使用。

    1. /**
    2. * 处理注册功能
    3. *
    4. * @param request
    5. * @param response
    6. * @throws ServletException
    7. * @throws IOException
    8. */
    9. protected void regist(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    10. UserService userService = new UserServiceImpl();
    11. // 获取请求的参数
    12. User user = WebUtils.copyParamToBean(request.getParameterMap(), new User());
    13. String code = request.getParameter("code");
    14. // 获取 Session 中的验证码
    15. HttpSession session = request.getSession();
    16. // KAPTCHA_SESSION_KEY 可以当作是验证码值的key
    17. String key = (String) session.getAttribute(KAPTCHA_SESSION_KEY);
    18. // 删除 Session 中的验证码
    19. // session.removeAttribute(KAPTCHA_SESSION_KEY);
    20. session.invalidate();
    21. // 检查 验证码是否正确
    22. if (code.equalsIgnoreCase(key)) {
    23. // 正确 检查 用户名是否可用
    24. if (userService.existsUsername(user.getUsername())) {
    25. // 不可用
    26. request.setAttribute("msg", "用户名已存在!");
    27. request.setAttribute("email", user.getEmail());
    28. // 跳回注册页面
    29. request.getRequestDispatcher("/pages/user/regist.jsp").forward(request, response);
    30. } else {
    31. // 可用 跳转到注册成功页面
    32. userService.regist(new User(user.getId(), user.getUsername(), user.getPassword(), user.getEmail()));
    33. request.getRequestDispatcher("/pages/user/regist_success.jsp").forward(request, response);
    34. }
    35. } else {
    36. // 不正确
    37. request.setAttribute("msg", "验证码错误!");
    38. request.setAttribute("username", user.getUsername());
    39. request.setAttribute("email", user.getEmail());
    40. // 跳回注册页面
    41. request.getRequestDispatcher("/pages/user/regist.jsp").forward(request, response);
    42. }
    43. }

    5.切换验证码

     给验证码绑定单机事件

    项目第六阶段:购物车

    1. 购物车模块分析

    2. 购物车模型编写

    2.1 编写CartItem类(生成方法略)

    1. /**
    2. * 购物车的商品项
    3. */
    4. public class CartItem {
    5. private Integer id;
    6. private String name;
    7. private Integer count;
    8. private BigDecimal price;
    9. private BigDecimal totalPrice;
    10. }

    2.2 编写Cart类

    1. /**
    2. * 购物车对象
    3. */
    4. public class Cart {
    5. // private Integer totalCount;
    6. // private BigDecimal totalPrice;
    7. /**
    8. * key 是商品编号,
    9. * value,是商品信息
    10. */
    11. private Map items = new LinkedHashMap<>();
    12. /**
    13. * 添加商品项
    14. *
    15. * @param cartItem
    16. */
    17. public void addItem(CartItem cartItem) {
    18. // 先查看购物车中是否已经添加过此商品,
    19. // 如果已添加,则数量累加,总金额更新,如果没有添加过,直接放到 集合中即可
    20. CartItem item = items.get(cartItem.getId());
    21. if (item == null) {
    22. // 之前没添加过此商品
    23. items.put(cartItem.getId(), cartItem);
    24. } else {
    25. // 之前已添加过此商品
    26. item.setCount(item.getCount() + 1); // 数量
    27. item.setTotalPrice(item.getPrice().multiply(new BigDecimal(item.getCount())));
    28. }
    29. }
    30. /**
    31. * 删除商品项
    32. *
    33. * @param id
    34. */
    35. public void deleteItem(Integer id) {
    36. items.remove(id);
    37. }
    38. /**
    39. * 清空购物车
    40. */
    41. public void clear() {
    42. items.clear();
    43. }
    44. /**
    45. * 修改商品数量
    46. *
    47. * @param id
    48. * @param count
    49. */
    50. public void updateCount(Integer id, Integer count) {
    51. // 先查看购物车中是否有此商品。如果有,修改商品数量,更新总金额
    52. CartItem item = items.get(id);
    53. if (item != null) {
    54. // 修改商品数量
    55. item.setCount(count);
    56. // 修改商品总金额
    57. item.setTotalPrice(item.getPrice().multiply(new BigDecimal(count)));
    58. }
    59. }
    60. public Integer getTotalCount() {
    61. Integer totalCount = 0;
    62. for (Map.Entry entry : items.entrySet()) {
    63. totalCount += entry.getValue().getCount();
    64. }
    65. return totalCount;
    66. }
    67. public BigDecimal getTotalPrice() {
    68. BigDecimal totalPrice = new BigDecimal(0);
    69. for (Map.Entry entry : items.entrySet()) {
    70. totalPrice = totalPrice.add(entry.getValue().getTotalPrice());
    71. }
    72. return totalPrice;
    73. }
    74. public Map getItems() {
    75. return items;
    76. }
    77. public void setItems(Map items) {
    78. this.items = items;
    79. }
    80. @Override
    81. public String toString() {
    82. return "Cart{" +
    83. "totalCount=" + getTotalCount() +
    84. ", totalPrice=" + getTotalPrice() +
    85. ", items=" + items +
    86. '}';
    87. }
    88. }

    2.3 测试Cart类

    1. public class CartTest {
    2. Cart cart = new Cart();
    3. @Test
    4. public void addItem() {
    5. cart.addItem(new CartItem(1, "java从入门到放弃", 1, new BigDecimal(1000), new BigDecimal(2000)));
    6. cart.addItem(new CartItem(1, "java从入门到放弃", 1, new BigDecimal(1000), new BigDecimal(2000)));
    7. cart.addItem(new CartItem(2, "java从入门到入土", 1, new BigDecimal(100), new BigDecimal(100)));
    8. System.out.println(cart);
    9. }
    10. @Test
    11. public void deleteItem() {
    12. cart.addItem(new CartItem(1, "java从入门到放弃", 1, new BigDecimal(1000), new BigDecimal(2000)));
    13. cart.addItem(new CartItem(1, "java从入门到放弃", 1, new BigDecimal(1000), new BigDecimal(2000)));
    14. cart.addItem(new CartItem(2, "java从入门到入土", 1, new BigDecimal(100), new BigDecimal(100)));
    15. cart.deleteItem(1);
    16. System.out.println(cart);
    17. }
    18. @Test
    19. public void clear() {
    20. cart.addItem(new CartItem(1, "java从入门到放弃", 1, new BigDecimal(1000), new BigDecimal(2000)));
    21. cart.addItem(new CartItem(1, "java从入门到放弃", 1, new BigDecimal(1000), new BigDecimal(2000)));
    22. cart.addItem(new CartItem(2, "java从入门到入土", 1, new BigDecimal(100), new BigDecimal(100)));
    23. cart.deleteItem(1);
    24. cart.clear();
    25. System.out.println(cart);
    26. }
    27. @Test
    28. public void updateCount() {
    29. cart.addItem(new CartItem(1, "java从入门到放弃", 1, new BigDecimal(1000), new BigDecimal(2000)));
    30. cart.addItem(new CartItem(1, "java从入门到放弃", 1, new BigDecimal(1000), new BigDecimal(2000)));
    31. cart.addItem(new CartItem(2, "java从入门到入土", 1, new BigDecimal(100), new BigDecimal(100)));
    32. cart.updateCount(2,20);
    33. System.out.println(cart);
    34. }
    35. }

    3. 加入购物车功能的实现

    步骤:
             1.在index.jsp 页面 给加入 购物车按钮添加绑定事件,使点击时可以跳到CartServlet程序
            2.编写 CartServlet程序
                    1. 获取请求的参数 商品编号
                    2. 调用 bookService.queryBookById(id):Book 得到图书的信息
                    3. 把图书信息,转换成为 CartItem 商品项
                    4. 调用 Cart.addItem(CartItem);添加商品项
                    5. 重定向回原来商品所在的地址页面
    1.在index.jsp 页面 给加入 购物车按钮添加绑定事件,使点击时可以跳到CartServlet程序

    2.编写 CartServlet程序

    1. /**
    2. * 加入购物车
    3. * @param request
    4. * @param response
    5. * @throws ServletException
    6. * @throws IOException
    7. */
    8. protected void addItem(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    9. System.out.println("进来了");
    10. // 1. 获取请求的参数 商品编号
    11. int id = WebUtils.parseInt(request.getParameter("id"), 0);
    12. // 2. 调用 bookService.queryBookById(id):Book 得到图书的信息
    13. Book book = bookService.queryBookById(id);
    14. // 3. 把图书信息,转换成为 CartItem 商品项
    15. CartItem cartItem = new CartItem(book.getId(), book.getName(), 1, book.getPrice(), book.getPrice());
    16. // 4. 调用 Cart.addItem(CartItem);添加商品项
    17. Cart cart = (Cart) request.getSession().getAttribute("cart");
    18. if (cart == null) {
    19. cart = new Cart();
    20. request.getSession().setAttribute("cart",cart);
    21. }
    22. cart.addItem(cartItem);
    23. // 5. 重定向回原来商品所在的地址页面
    24. // Referer 可以获取当前页面地址
    25. System.out.println(cart);
    26. System.out.println("当前页面地址:" + request.getHeader("Referer"));
    27. response.sendRedirect(request.getHeader("Referer"));
    28. }

    4. 购物车的展示

    1. <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
    2. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    3. html>
    4. <html>
    5. <head>
    6. <meta charset="UTF-8">
    7. <title>购物车title>
    8. <%@include file="/pages/common/head.jsp" %>
    9. head>
    10. <body>
    11. <div id="header">
    12. <img class="logo_img" alt="" src="static/img/logo.gif">
    13. <span class="wel_word">购物车span>
    14. <%@include file="/pages/common/success_menu.jsp" %>
    15. div>
    16. <div id="main">
    17. <table>
    18. <tr>
    19. <td>商品名称td>
    20. <td>数量td>
    21. <td>单价td>
    22. <td>金额td>
    23. <td>操作td>
    24. tr>
    25. <c:if test="${empty sessionScope.cart.items}">
    26. <tr>
    27. <td colspan="5">
    28. <a href="index.jsp"> 亲,当前购物车为空!快跟小伙伴们去浏览商品吧!!!a>
    29. td>
    30. tr>
    31. c:if>
    32. <c:if test="${not empty sessionScope.cart.items}">
    33. <c:forEach items="${sessionScope.cart.items}" var="item">
    34. <tr>
    35. <td>${item.value.name}td>
    36. <td>${item.value.count}td>
    37. <td>${item.value.price}td>
    38. <td>${item.value.totalPrice}td>
    39. <td><a href="#">删除a>td>
    40. tr>
    41. c:forEach>
    42. c:if>
    43. table>
    44. <c:if test="${not empty sessionScope.cart.items}">
    45. <div class="cart_info">
    46. <span class="cart_span">购物车中共有<span class="b_count">${sessionScope.cart.totalCount}span>件商品span>
    47. <span class="cart_span">总金额<span class="b_price">${sessionScope.cart.totalPrice}span>元span>
    48. <span class="cart_span"><a href="#">清空购物车a>span>
    49. <span class="cart_span"><a href="pages/cart/checkout.jsp">去结账a>span>
    50. div>
    51. c:if>
    52. div>
    53. <%@include file="/pages/common/footer.jsp" %>
    54. body>
    55. html>

    5. 删除购物车商品项

    步骤:

            1 .给删除添加请求地址

            2. 编写cartServlet程序

            3. 给删除添加确认提示操作

    1 .给删除添加请求地址

     2. 编写cartServlet程序

    1. /**
    2. * 删除商品项
    3. * @param request
    4. * @param response
    5. * @throws ServletException
    6. * @throws IOException
    7. */
    8. protected void deleteItem(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    9. // 获取商品项编号
    10. int id = WebUtils.parseInt(request.getParameter("id"), 0);
    11. // 获取购物车对象
    12. Cart cart = (Cart) request.getSession().getAttribute("cart");
    13. if (cart != null) {
    14. // 删除 了购物车商品项
    15. cart.deleteItem(id);
    16. // 重定向回原来商品所在的地址页面
    17. response.sendRedirect(request.getHeader("Referer"));
    18. }
    19. }

      3. 给删除添加确认提示操作

    6. 清空购物车

    步骤:

            1 .给清除功能添加请求地址,并添加id属性

            2. 编写cartServlet程序

            3. 给删除添加确认提示操作

    1 .给清除功能添加请求地址,并添加id属性

    2. 编写cartServlet程序
    1. /**
    2. * 清空购物车
    3. * @param request
    4. * @param response
    5. * @throws ServletException
    6. * @throws IOException
    7. */
    8. protected void clear(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    9. //获取购物车对象
    10. Cart cart = (Cart) request.getSession().getAttribute("cart");
    11. if (cart != null) {
    12. //清空购物车
    13. cart.clear();
    14. // 重定向回原来商品所在的地址页面
    15. response.sendRedirect(request.getHeader("referer"));
    16. }
    17. }

    3. 给删除添加确认提示操作

    1. // 给清空购物车绑定事件
    2. $(function (){
    3. $("#clearCart").click(function (){
    4. return confirm("你确定要清空购物车吗?");
    5. });
    6. });

    7. 修改购物车商品数量

    思路:

    步骤:

            1 .在 数量列 添加文本框,并绑定事件

            2. 编写cartServlet程序

    1 .在 数量列 添加文本框,并绑定事件

    1. // 给修改数量绑定事件
    2. $(".updateCount").change(function () {
    3. // 获取商品id
    4. var id = $(this).attr("bookId");
    5. // 获取商品名称
    6. let name = $(this).parent().parent().find(":first").text();
    7. // 获取商品数量
    8. let count = this.value;
    9. if (confirm("你确定要将【" + name + "】的数量修改成:" + count + "吗")) {
    10. //发起请求。给服务器保存修改
    11. location.href = "cartServlet?action=updateCount&id=" + id + "&count=" + count;
    12. } else {
    13. // defaultValue 属性是表单项 Dom 对象的属性。它表示默认的 value 属性值。
    14. this.value = this.defaultValue;
    15. }
    16. });

     2. 编写cartServlet程序

    1. /**
    2. * 修改商品数量
    3. *
    4. * @param request
    5. * @param response
    6. * @throws ServletException
    7. * @throws IOException
    8. */
    9. protected void updateCount(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    10. // 获取请求的参数 商品编号 、商品数量
    11. int id = WebUtils.parseInt(request.getParameter("id"), 0);
    12. int count = WebUtils.parseInt(request.getParameter("count"), 1);
    13. // 获取购物车对象
    14. Cart cart = (Cart) request.getSession().getAttribute("cart");
    15. if (cart != null) {
    16. // 修改商品数量
    17. cart.updateCount(id, count);
    18. // 重定向返回商品原来的地址
    19. response.sendRedirect(request.getHeader("Referer"));
    20. }
    21. }

    8. 首页,购物车数据回显

    步骤:

            1.在添加商品到购物车的时候,保存最后一个添加的商品名称

            2.在 pages/client/index.jsp 页面中输出购物车信息

     1.在添加商品到购物车的时候,保存最后一个添加的商品名称

     2.在 pages/client/index.jsp 页面中输出购物车信息

    1. <c:if test="${empty sessionScope.cart.items}">
    2. <div style="text-align: center">
    3. <span> span>
    4. <div>
    5. <span style="color: red">您当前的购物车里没有商品哦span>
    6. div>
    7. div>
    8. c:if>
    9. <c:if test="${not empty sessionScope.cart.items}">
    10. <div style="text-align: center">
    11. <span>您的购物车中有${sessionScope.cart.totalCount}件商品span>
    12. <div>
    13. 您刚刚将<span style="color: red">${sessionScope.lastName}span>加入到了购物车中
    14. div>
    15. div>
    16. c:if>

    书城项目第七阶段 -- 订单

    1. 订单模块的分析

    2. 创建订单模块的数据库表

    1. USE book;
    2. CREATE TABLE t_order(
    3. order_id VARCHAR(50) PRIMARY KEY,
    4. create_time DATETIME ,
    5. price DECIMAL(11,2),
    6. `status` INT,
    7. user_id INT,
    8. FOREIGN KEY (user_id) REFERENCES t_book(id)
    9. );
    10. CREATE TABLE t_order_item(
    11. id INT PRIMARY KEY AUTO_INCREMENT,
    12. name VARCHAR(100),
    13. count INT,
    14. price DECIMAL(11,2),
    15. total_price DECIMAL(11,2),
    16. order_id VARCHAR(50),
    17. FOREIGN KEY (order_id) REFERENCES t_order(order_id)
    18. );

    3. 创建订单模块的数据模型

    1. public class Order {
    2. private String orderId;
    3. private Date createTime;
    4. private BigDecimal price;
    5. // 0 未发货,1 已发货,2 表示已签收
    6. private Integer status = 0;
    7. private Integer userId;
    8. }
    1. public class OrderItem {
    2. private Integer id;
    3. private String name;
    4. private Integer count;
    5. private BigDecimal price;
    6. private BigDecimal totalPrice;
    7. private String orderId;
    8. }

    4. 编写订单模块的 Dao 程序和测试

    4.1 OrderDao 接口

    1. public interface OrderDao {
    2. /**
    3. * 保存订单
    4. * @param order
    5. * @return
    6. */
    7. public int saveOrder(Order order);
    8. }

    4.2 OrderDao 实现

    1. public class OrderDaoImpl extends BaseDao implements OrderDao {
    2. @Override
    3. public int saveOrder(Order order) {
    4. String sql = "insert into t_order(order_id,create_time,price,`status`,user_id) values(?,?,?,?,?)";
    5. return update(sql, order.getOrderId(), order.getCreateTime(), order.getPrice(), order.getStatus(), order.getUserId());
    6. }
    7. }

    4.3 OrderItemDao 接口

    1. public interface OrderItemDao {
    2. /**
    3. * 保存订单项
    4. * @param orderItem
    5. * @return
    6. */
    7. public int saveOrderItem(OrderItem orderItem);
    8. }

    4.4 OrderItemDao 实现

    1. public class OrderItemDaoImpl extends BaseDao implements OrderItemDao {
    2. @Override
    3. public int saveOrderItem(OrderItem orderItem) {
    4. String sql = "insert into t_order_item(name,count,price,total_price,order_id) values (?,?,?,?,?)";
    5. return update(sql, orderItem.getName(), orderItem.getCount(), orderItem.getPrice(), orderItem.getTotalPrice(), orderItem.getOrderId());
    6. }
    7. }

    4.5 测试

    1. public class OrderDaoTest {
    2. private OrderDao orderDao = new OrderDaoImpl();
    3. @Test
    4. public void saveOrder() {
    5. orderDao.saveOrder(new Order("1234567891",new Date(),new BigDecimal(100),0, 1));
    6. orderDao.saveOrder(new Order("12345678912",new Date(),new BigDecimal(100),0, 1));
    7. orderDao.saveOrder(new Order("1234567893",new Date(),new BigDecimal(100),0, 1));
    8. }
    9. }
    1. public class OrderItemDaoTest {
    2. private OrderItemDao orderItemDao = new OrderItemDaoImpl();
    3. @Test
    4. public void saveOrderItem() {
    5. orderItemDao.saveOrderItem(new OrderItem(null,"java 从入门到精通", 1,new BigDecimal(100),new BigDecimal(100),"1234567891"));
    6. orderItemDao.saveOrderItem(new OrderItem(null,"java 从入门到精通11", 1,new BigDecimal(1000),new BigDecimal(100),"12345678912"));
    7. orderItemDao.saveOrderItem(new OrderItem(null,"java 从入门到精通22", 1,new BigDecimal(10000),new BigDecimal(100),"1234567893"));
    8. }
    9. }

    5. 编写订单模块的 Service 和测试

    5.1 OrderService接口

    1. public interface OrderService {
    2. public String createOrder(Cart cart, Integer userId);
    3. }

    5.2 OrderServiceImpl 编写

    1. public class OrderServiceImpl extends BaseDao implements OrderService {
    2. private OrderDao orderDao = new OrderDaoImpl();
    3. private OrderItemDao orderItemDao = new OrderItemDaoImpl();
    4. @Override
    5. public String createOrder(Cart cart, Integer userId) {
    6. // 获取唯一性的订单号
    7. String orderId = System.currentTimeMillis() + "" + userId;
    8. // 创建一个订单对象
    9. Order order = new Order(orderId, new Date(), cart.getTotalPrice(), 0, userId);
    10. // 保存订单
    11. orderDao.saveOrder(order);
    12. // 遍历购物车中每一个商品项转换成为订单项保存到数据库
    13. for (Map.Entry item : cart.getItems().entrySet()) {
    14. // 获取每一个购物车中的商品项
    15. CartItem cartItem = item.getValue();
    16. // 转换为每一个订单项
    17. OrderItem orderItem = new OrderItem(null, cartItem.getName(),
    18. cartItem.getCount(), cartItem.getPrice(), cartItem.getTotalPrice(), orderId);
    19. // 保存订单项到数据库
    20. orderItemDao.saveOrderItem(orderItem);
    21. }
    22. // 清空购物车
    23. cart.clear();
    24. // 返回订单号
    25. return orderId;
    26. }
    27. }

    5.3 测试

    1. public class OrderServiceTest {
    2. private OrderService orderService = new OrderServiceImpl();
    3. @Test
    4. public void createOrder() {
    5. Cart cart = new Cart();
    6. cart.addItem(new CartItem(1, "java从入门到精通", 1, new BigDecimal(1000), new BigDecimal(1000)));
    7. cart.addItem(new CartItem(1, "java从入门到精通", 1, new BigDecimal(1000), new BigDecimal(1000)));
    8. cart.addItem(new CartItem(2, "数据结构与算法", 1, new BigDecimal(100), new BigDecimal(100)));
    9. OrderService orderService = new OrderServiceImpl();
    10. System.out.println("订单号是:" + orderService.createOrder(cart, 1));
    11. }
    12. }

    6. 编写订单模块的 web 层和页面联调

    6.1 生成订单功能

    步骤:
            1. 编写OrderServlet 程序
            2. 修改 pages/cart/cart.jsp 页面,结账的请求地址
            3. 修改 pages/cart/checkout.jsp 页面,输出订单号
    1. 编写OrderServlet 程序
    1. @WebServlet(name = "OrderServlet ", value = "/orderServlet ")
    2. public class OrderServlet extends BaseServlet {
    3. private OrderService orderService = new OrderServiceImpl();
    4. protected void createOrder(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    5. // 先获取 Cart 购物车对象
    6. Cart cart = (Cart) request.getSession().getAttribute("cart");
    7. // 获取 Userid
    8. User loginUser = (User) request.getSession().getAttribute("user");
    9. // 判断用户是否存在,若不存在,则转发到登录界面
    10. if (loginUser == null) {
    11. request.getRequestDispatcher("/pages/user/login.jsp").forward(request, response);
    12. return;
    13. }
    14. // 调用 orderService.createOrder(Cart,Userid);生成订单 并返回订单号
    15. // 获取用户id
    16. Integer id = loginUser.getId();
    17. System.out.println(id);
    18. System.out.println(loginUser);
    19. String orderId = orderService.createOrder(cart, id);
    20. // 将订单号保存到Session域中
    21. request.getSession().setAttribute("orderId", orderId);
    22. // 将页面请求重定向到checkout.jsp界面
    23. response.sendRedirect(request.getContextPath() + "/pages/cart/checkout.jsp");
    24. }
    25. }

     2. 修改 pages/cart/cart.jsp 页面,结账的请求地址

    3. 修改 pages/cart/checkout.jsp 页面,输出订单号

    6.2 获取所有订单功能(管理员)

    步骤:
            1. 编写OrderServlet 程序
            2. 修改 manager_menu.jsp 页面,订单管理的请求地址
            3. 修改 pages/manager/order_manager.jsp 页面,遍历订单
    1. 编写OrderServlet 程序
    1. /**
    2. * 查看所有订单
    3. *
    4. * @param request
    5. * @param response
    6. * @throws ServletException
    7. * @throws IOException
    8. */
    9. protected void showAllOrders(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    10. // 1 通过 orderService 查询全部订单
    11. List orders = orderService.showAllOrders();
    12. // 2 把全部订单保存到 Request 域中
    13. request.setAttribute("orders", orders);
    14. // 3、请求转发到/pages/order/order.jsp 页面
    15. request.getRequestDispatcher("/pages/manager/order_manager.jsp").forward(request, response);
    16. }

    2. 修改 manager_menu.jsp 页面,订单管理的请求地址

    3. 修改 pages/manager/order_manager.jsp 页面,遍历订单
    1. <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
    2. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    3. html>
    4. <html>
    5. <head>
    6. <meta charset="UTF-8">
    7. <title>订单管理title>
    8. <%@include file="/pages/common/head.jsp"%>
    9. head>
    10. <body>
    11. <div id="header">
    12. <img class="logo_img" alt="" src="static/img/logo.gif">
    13. <span class="wel_word">订单管理系统span>
    14. <%@include file="/pages/common/manager_menu.jsp"%>
    15. div>
    16. <div id="main">
    17. <table>
    18. <tr>
    19. <td>日期td>
    20. <td>金额td>
    21. <td>详情td>
    22. <td>发货td>
    23. tr>
    24. <c:forEach items="${requestScope.orders}" var="order">
    25. <tr>
    26. <td>${order.createTime}td>
    27. <td>${order.price}td>
    28. <td><a href="#">查看详情a>td>
    29. <c:if test="${order.status == 0}">
    30. <td><a href="orderServlet?action=sendOrder&orderId=${order.orderId}">点击发货a>td>
    31. c:if>
    32. <c:if test="${order.status == 1}">
    33. <td>等待收货td>
    34. c:if>
    35. <c:if test="${order.status == 2}">
    36. <td>已完成td>
    37. c:if>
    38. tr>
    39. c:forEach>
    40. table>
    41. div>
    42. <%@include file="/pages/common/footer.jsp"%>
    43. body>
    44. html>

    6.3 管理员点击发货功能

    步骤:
            1. 修改 pages/manager/order_manager.jsp 页面,点击发货的请求地址
            2. 编写OrderServlet 程序
    1. 修改 pages/manager/order_manager.jsp 页面,点击发送的v

    2. 编写OrderServlet 程序

    1. /**
    2. * 管理员发货功能
    3. * @param request
    4. * @param response
    5. * @throws ServletException
    6. * @throws IOException
    7. */
    8. protected void sendOrder(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    9. // 获取参数 orderId
    10. String orderId = request.getParameter("orderId");
    11. orderService.sendOrder(orderId);
    12. response.sendRedirect(request.getHeader("Referer"));
    13. }

    6.4 查看订单详情功能

    步骤:
            1. 修改order_manager.jsp 和 order.jsp页,给查看详情添加请求地址
            2. 编写OrderServlet 程序  
            3. 修改order_detail页面,遍历数据

    1.修改order_manager.jsp 和 order.jsp页,给查看详情添加请求地址

     2. 编写OrderServlet 程序 

    1. /**
    2. * 查看订单详情
    3. *
    4. * @param request
    5. * @param response
    6. * @throws ServletException
    7. * @throws IOException
    8. */
    9. protected void showOrderDetail(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    10. // 获取参数 orderId
    11. String orderId = request.getParameter("orderId");
    12. // 获取订单的详情信息
    13. List orderItems = orderService.showOrderDetail(orderId);
    14. // 将订单的详情信息保存到Request域中
    15. request.setAttribute("orderItems", orderItems);
    16. // 请求转发到订单详情页面中
    17. request.getRequestDispatcher("/pages/order/order_detail.jsp").forward(request, response);
    18. }

    3. 修改order_detail页面,遍历数据

    1. <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
    2. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    3. html>
    4. <html>
    5. <head>
    6. <meta charset="UTF-8">
    7. <title>订单详情title>
    8. <%@include file="/pages/common/head.jsp" %>
    9. head>
    10. <body>
    11. <div id="header">
    12. <img class="logo_img" alt="" src="static/img/logo.gif">
    13. <span class="wel_word">订单详情span>
    14. <%@include file="/pages/common/success_menu.jsp" %>
    15. div>
    16. <div id="main">
    17. <table>
    18. <tr>
    19. <td>商品名称td>
    20. <td>数量td>
    21. <td>单价td>
    22. <td>金额td>
    23. tr>
    24. <c:if test="${empty requestScope.orderItems}">
    25. <tr>
    26. <td colspan="5">
    27. <a href="index.jsp">暂无订单a>
    28. td>
    29. tr>
    30. c:if>
    31. <c:if test="${not empty requestScope.orderItems}">
    32. <c:forEach items="${requestScope.orderItems}" var="item">
    33. <tr>
    34. <td>${item.name}td>
    35. <td>${item.count}td>
    36. <td>${item.price}td>
    37. <td>${item.totalPrice}td>
    38. tr>
    39. c:forEach>
    40. c:if>
    41. table>
    42. div>
    43. <%@include file="/pages/common/footer.jsp" %>
    44. body>
    45. html>

    6.5 查看我的订单功能

    步骤:
            1. 修改success_menu.jsp和index.jsp页面,给 我的订单 添加请求地址
            2. 编写OrderServlet 程序  
            3. 修改order页面,遍历数据
    1. 修改success_menu.jsp和index.jsp页面,给 我的订单 添加请求地址
    2. 编写OrderServlet 程序  
    1. /**
    2. * 查看我的订单
    3. *
    4. * @param request
    5. * @param response
    6. * @throws ServletException
    7. * @throws IOException
    8. */
    9. protected void showMyOrders(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    10. // 获取参数 orderId
    11. int userId = WebUtils.parseInt(request.getParameter("userId"), 0);
    12. if (userId != 0) {
    13. // 获取订单的详情信息
    14. List myOrders = orderService.showMyOrders(userId);
    15. // 将订单信息保存到Request域中
    16. request.setAttribute("myOrders",myOrders);
    17. // 请求转发到我的订单页面中
    18. request.getRequestDispatcher("/pages/order/order.jsp").forward(request,response);
    19. }
    20. }

    3. 修改order页面,遍历数据

    1. <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
    2. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    3. html>
    4. <html>
    5. <head>
    6. <meta charset="UTF-8">
    7. <title>我的订单title>
    8. <%@include file="/pages/common/head.jsp" %>
    9. <style type="text/css">
    10. h1 {
    11. text-align: center;
    12. margin-top: 200px;
    13. }
    14. style>
    15. head>
    16. <body>
    17. <div id="header">
    18. <img class="logo_img" alt="" src="static/img/logo.gif">
    19. <span class="wel_word">我的订单span>
    20. <%@include file="/pages/common/success_menu.jsp" %>
    21. div>
    22. <div id="main">
    23. <table>
    24. <tr>
    25. <td>订单编号td>
    26. <td>日期td>
    27. <td>金额td>
    28. <td>状态td>
    29. <td>详情td>
    30. tr>
    31. <c:forEach items="${requestScope.myOrders}" var="order">
    32. <tr>
    33. <td>${order.orderId}td>
    34. <td>${order.createTime}td>
    35. <td>${order.price}td>
    36. <c:if test="${order.status == 0}">
    37. <td>未发货td>
    38. c:if>
    39. <c:if test="${order.status == 1}">
    40. <td><a href="orderServlet?action=receiverOrder&orderId=${order.orderId}">确认收货a> td>
    41. c:if>
    42. <c:if test="${order.status == 2}">
    43. <td>已完成td>
    44. c:if>
    45. <td><a href="orderServlet?action=showOrderDetail&orderId=${order.orderId}">查看详情a>td>
    46. tr>
    47. c:forEach>
    48. table>
    49. div>
    50. <%@include file="/pages/common/footer.jsp" %>
    51. body>
    52. html>

    6.6 签收订单功能

    步骤:
            1. 修改order.jsp页面,给 确认收货 添加a标签及请求地址
            2. 编写OrderServlet 程序  
    1. 修改order.jsp页面,给 确认收货 添加a标签及请求地址

    2. 编写OrderServlet 程序  
    1. /**
    2. * 签收订单功能
    3. * @param request
    4. * @param response
    5. * @throws ServletException
    6. * @throws IOException
    7. */
    8. protected void receiverOrder(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    9. // 获取参数 orderId
    10. String orderId = request.getParameter("orderId");
    11. orderService.receiverOrder(orderId);
    12. response.sendRedirect(request.getHeader("Referer"));
    13. }

    书城项目第八阶段

    1.使用 Filter 过滤器拦截/pages/manager/所有内容,实现权限检查

    1. @WebFilter(filterName = "ManagerFilter")
    2. public class ManagerFilter implements Filter {
    3. public void init(FilterConfig config) throws ServletException {
    4. }
    5. public void destroy() {
    6. }
    7. @Override
    8. public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
    9. HttpServletRequest req = (HttpServletRequest) request;
    10. Object user = req.getSession().getAttribute("user");
    11. if (user == null) {
    12. request.getRequestDispatcher("/pages/user/login.jsp").forward(request, response);
    13. return;
    14. }else{
    15. chain.doFilter(request, response);
    16. }
    17. }
    18. }

    xml代码:

    1. <filter>
    2. <filter-name>ManagerFilterfilter-name>
    3. <filter-class>com.chenyixin.book.filter.ManagerFilterfilter-class>
    4. filter>
    5. <filter-mapping>
    6. <filter-name>ManagerFilterfilter-name>
    7. <url-pattern>/pages/manager/*url-pattern>
    8. <url-pattern>/manager/bookServleturl-pattern>
    9. filter-mapping>

    2. 使用 Filter 和 ThreadLocal 组合管理事务

    2.1 使用 ThreadLocal 来确保所有 dao 操作都在同一个 Connection 连接对象中完

    原理示意图

    JdbcUtils 工具类的修改:
    1. public class JdbcUtils {
    2. private static DruidDataSource dataSource;
    3. private static ThreadLocal threadLocal = new ThreadLocal<>();
    4. // 在静态代码块中创建数据库连接
    5. static {
    6. try {
    7. // 获取配置文件jdbc.properties对象
    8. Properties properties = new Properties();
    9. // 读取jdbc.properties属性配置文件
    10. InputStream inputStream = JdbcUtils.class.getClassLoader().getResourceAsStream("jdbc.properties");
    11. // 从流中加载数据
    12. properties.load(inputStream);
    13. // 创建数据库连接池
    14. dataSource = (DruidDataSource) DruidDataSourceFactory.createDataSource(properties);
    15. } catch (Exception e) {
    16. e.printStackTrace();
    17. }
    18. }
    19. /**
    20. * 获取数据库连接池中的连接
    21. *
    22. * @return 如果返回 null,说明获取连接失败
      有值就是获取连接成功
    23. */
    24. public static Connection getConnection() {
    25. Connection conn = threadLocal.get();
    26. if (conn == null) {
    27. try {
    28. conn = dataSource.getConnection(); //从数据库连接池中获取连接
    29. threadLocal.set(conn); // 保存到 ThreadLocal 对象中,供后面的 jdbc 操作使用
    30. conn.setAutoCommit(false); // 设置手动管理事务
    31. } catch (SQLException e) {
    32. throw new RuntimeException(e);
    33. }
    34. }
    35. return conn;
    36. }
    37. /**
    38. * 提交事务,并关闭释放连接
    39. */
    40. public static void commitAndClose(){
    41. Connection conn = threadLocal.get();
    42. if (conn != null) { // 如果不等于 null,说明 之前使用过连接,操作过数据库
    43. try {
    44. conn.commit(); //提交事务
    45. } catch (SQLException e) {
    46. e.printStackTrace();
    47. }finally {
    48. try {
    49. conn.close(); // 关闭资源
    50. } catch (SQLException e) {
    51. e.printStackTrace();
    52. }
    53. }
    54. }
    55. // 一定要执行 remove 操作,否则就会出错。(因为 Tomcat 服务器底层使用了线程池技术)
    56. threadLocal.remove();
    57. }
    58. /**
    59. * 回滚事务,并关闭释放连接
    60. */
    61. public static void rollbackAndClose(){
    62. Connection conn = threadLocal.get();
    63. if (conn != null) { // 如果不等于 null,说明 之前使用过连接,操作过数据库
    64. try {
    65. conn.commit(); //回滚事务
    66. } catch (SQLException e) {
    67. e.printStackTrace();
    68. }finally {
    69. try {
    70. conn.close(); // 关闭资源
    71. } catch (SQLException e) {
    72. e.printStackTrace();
    73. }
    74. }
    75. }
    76. // 一定要执行 remove 操作,否则就会出错。(因为 Tomcat 服务器底层使用了线程池技术)
    77. threadLocal.remove();
    78. }
    79. /**
    80. * 关闭连接,放回数据库连接池
    81. *
    82. * @param connection 放入要关闭的连接对象
    83. */
    84. // public static void close(Connection connection) {
    85. // try {
    86. // if (connection != null) {
    87. // connection.close();
    88. // }
    89. // } catch (SQLException e) {
    90. // e.printStackTrace();
    91. // }
    92. // }
    93. }
    修改 BaseDao
    1. public abstract class BaseDao {
    2. private final QueryRunner queryRunner = new QueryRunner();
    3. /**
    4. * 用来执行:Insert\Update\Delete 语句
    5. *
    6. * @param sql 传入要执行的sql语句
    7. * @param args 参数列表
    8. * @return 返回-1表示update失败,否则成功
    9. */
    10. public int update(String sql, Object... args) {
    11. Connection conn = JdbcUtils.getConnection();
    12. try {
    13. return queryRunner.update(conn, sql, args);
    14. } catch (SQLException e) {
    15. throw new RuntimeException(e);
    16. }
    17. }
    18. /**
    19. * 查询返回一个 javaBean 的 sql 语句
    20. * @param type 返回的对象类型
    21. * @param sql 执行的 sql 语句
    22. * @param args sql 对应的参数值
    23. * @param 返回的类型的泛型
    24. * @return 若返回为null,则查看失败
    25. */
    26. public T queryForOne(Class type, String sql, Object... args) {
    27. Connection conn = JdbcUtils.getConnection();
    28. try {
    29. return queryRunner.query(conn, sql, new BeanHandler(type), args);
    30. } catch (SQLException e) {
    31. throw new RuntimeException(e);
    32. }
    33. }
    34. /**
    35. * 查询返回多个 javaBean 的 sql 语句
    36. *
    37. * @param type 返回的对象类型
    38. * @param sql 执行的 sql 语句
    39. * @param args sql 对应的参数值
    40. * @param 返回的类型的泛型
    41. * @return 若返回为null, 则查看失败
    42. */
    43. public List queryForList(Class type, String sql, Object... args) {
    44. Connection conn = JdbcUtils.getConnection();
    45. try {
    46. return queryRunner.query(conn, sql, new BeanListHandler(type), args);
    47. } catch (SQLException e) {
    48. throw new RuntimeException(e);
    49. }
    50. }
    51. /**
    52. * 执行返回一行一列的 sql 语句
    53. * @param sql 执行的 sql 语句
    54. * @param args sql对应的参数
    55. * @return 若返回为null, 则查看失败
    56. */
    57. public Object queryForSingleValue(String sql,Object... args) {
    58. Connection conn = JdbcUtils.getConnection();
    59. try {
    60. return queryRunner.query(conn,sql,new ScalarHandler(),args);
    61. } catch (SQLException e) {
    62. throw new RuntimeException(e);
    63. }
    64. }
    65. }

    2.2 使用 Filter 过滤器统一给所有的 Service 方法都加上 try-catch,来进行实现的管理

    原理分析图:

    Filter 类代码:
    1. public class TransactionFilter implements Filter {
    2. public void init(FilterConfig config) throws ServletException {
    3. }
    4. public void destroy() {
    5. }
    6. @Override
    7. public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
    8. try {
    9. chain.doFilter(request, response);
    10. JdbcUtils.commitAndClose(); // 提交事务
    11. } catch (Exception e) {
    12. JdbcUtils.rollbackAndClose(); // 回滚事务
    13. e.printStackTrace();
    14. }
    15. }
    16. }
    在 web.xml 中的配置:
    1. <filter>
    2. <filter-name>TransactionFilterfilter-name>
    3. <filter-class>com.chenyixin.book.filter.TransactionFilterfilter-class>
    4. filter>
    5. <filter-mapping>
    6. <filter-name>TransactionFilterfilter-name>
    7. <url-pattern>/*url-pattern>
    8. filter-mapping>
    一定要记得把 BaseServlet 中的异常往外抛给 Filter 过滤器:
    1. @Override
    2. protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    3. // 解决post请求中文乱码问题
    4. // 一定要在获取请求参数之前调用才有效
    5. request.setCharacterEncoding("UTF-8");
    6. String action = request.getParameter("action");
    7. // 获取 action 业务鉴别字符串,获取相应的业务 方法反射对象
    8. try {
    9. Method method = this.getClass().getDeclaredMethod(action, HttpServletRequest.class, HttpServletResponse.class);
    10. // 调用目标业务 方法
    11. method.invoke(this, request, response);
    12. } catch (Exception e) {
    13. // e.printStackTrace();
    14. throw new RuntimeException(e);
    15. }
    16. }

    2.3 将所有异常都统一交给 Tomcat,让 Tomcat 展示友好的错误信息页面

    web.xml 中我们可以通过错误页面配置来进行管理
    1. <error-page>
    2. <error-code>404error-code>
    3. <location>/pages/error/error404.jsplocation>
    4. error-page>
    5. <error-page>
    6. <error-code>500error-code>
    7. <location>/pages/error/error500.jsplocation>
    8. error-page>

    error404.jsp页面:

    1. <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
    2. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    3. html>
    4. <html>
    5. <head>
    6. <meta charset="UTF-8">
    7. <title>error404title>
    8. <%-- 静态包含 base标签、css样式、jQuery文件 --%>
    9. <%@ include file="/pages/common/head.jsp"%>
    10. head>
    11. <body>
    12. <h1>很抱歉。您访问的页面不存在,或已经被删除!!! h1><br/>
    13. <h1><a href="index.jsp">返回首页a>h1>
    14. body>
    15. html>

    error500.jsp页面:

    1. <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
    2. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    3. html>
    4. <html>
    5. <head>
    6. <meta charset="UTF-8">
    7. <title>error404title>
    8. <%-- 静态包含 base标签、css样式、jQuery文件 --%>
    9. <%@ include file="/pages/common/head.jsp"%>
    10. head>
    11. <body>
    12. <h1>很抱歉,您访问的后台程序出现了错误,程序猿小哥,正在努力的为您抢修!!! h1><br/>
    13. <h1><a href="index.jsp">返回首页a>h1>
    14. body>
    15. html>

    书城项目第九阶段

    1. 使用 AJAX 验证用户名是否可用

    步骤:

            1.在UserServlet 程序中添加 ajaxExistsUsername 方法

            2regist.jsp 页面中的代码

    1.在UserServlet 程序中添加 ajaxExistsUsername 方法
    1. /**
    2. * 注册用户名的失去焦点事件,判断用户名是否存在
    3. *
    4. * @param request
    5. * @param response
    6. * @throws ServletException
    7. * @throws IOException
    8. */
    9. protected void ajaxExistsUsername(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    10. // 获取请求的参数 username
    11. String username = request.getParameter("username");
    12. // 调用 userService.existsUsername();
    13. boolean existsUsername = userService.existsUsername(username);
    14. // 把返回的结果封装成为 map 对象
    15. Map map = new HashMap<>();
    16. map.put("existsUsername", existsUsername);
    17. Gson gson = new Gson();
    18. String json = gson.toJson(map);
    19. response.getWriter().write(json);
    20. }

    2regist.jsp 页面中的代码

    1. // 给用户名添加失去焦点事件
    2. $("#username").blur(function () {
    3. // 获取用户名
    4. var username = this.value;
    5. if (username != "") {
    6. $.getJSON("userServlet", "action=ajaxExistsUsername&username=" + username, function (data) {
    7. if (data.existsUsername) {
    8. $("span.errorMsg").text("用户名已存在!");
    9. } else {
    10. $("span.errorMsg").text("用户名可用!");
    11. }
    12. });
    13. } else {
    14. $("span.errorMsg").text("用户名不能为空!");
    15. }
    16. });

    2. 使用 AJAX 修改把商品添加到购物车

    CartServlet 程序:
    1. /**
    2. * 加入购物车
    3. *
    4. * @param request
    5. * @param response
    6. * @throws ServletException
    7. * @throws IOException
    8. */
    9. protected void ajaxAddItem(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    10. // 1. 获取请求的参数 商品编号
    11. int id = WebUtils.parseInt(request.getParameter("id"), 0);
    12. // 2. 调用 bookService.queryBookById(id):Book 得到图书的信息
    13. Book book = bookService.queryBookById(id);
    14. // 3. 把图书信息,转换成为 CartItem 商品项
    15. CartItem cartItem = new CartItem(book.getId(), book.getName(), 1, book.getPrice(), book.getPrice());
    16. // 4. 调用 Cart.addItem(CartItem);添加商品项
    17. Cart cart = (Cart) request.getSession().getAttribute("cart");
    18. if (cart == null) {
    19. cart = new Cart();
    20. request.getSession().setAttribute("cart", cart);
    21. }
    22. cart.addItem(cartItem);
    23. // 最后一个添加商品的名称
    24. request.getSession().setAttribute("lastName", cartItem.getName());
    25. // 返回购物车总的商品数量和最后一个添加的商品名称
    26. Map map = new HashMap<>();
    27. map.put("totalCount", cart.getTotalCount());
    28. map.put("lastName", cartItem.getName());
    29. Gson gson = new Gson();
    30. String resultMapJsonString = gson.toJson(map);
    31. response.getWriter().write(resultMapJsonString);
    32. }

    index.jsp页面

    1. <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
    2. <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    3. html>
    4. <html>
    5. <head>
    6. <meta charset="UTF-8">
    7. <title>书城首页title>
    8. <%@include file="/pages/common/head.jsp" %>
    9. <script type="text/javascript">
    10. $(function () {
    11. $(".addToCart").click(function () {
    12. /**
    13. * 在事件响应的 function 函数 中,有一个 this 对象,这个 this 对象,是当前正在响应事件的 dom 对象
    14. * attr() 可以设置和获取属性的值
    15. * location.href: 返回当前页面的完整的URL地址;
    16. */
    17. var bookId = $(this).attr("bookId");
    18. // location.href = "cartServlet?action=addItem&id=" + bookId;
    19. $.getJSON("cartServlet", "action=ajaxAddItem&id=" + bookId, function (data) {
    20. $(".totalCount").text("您的购物车中有" + data.totalCount + "件商品");
    21. $(".lastName").text(data.lastName);
    22. });
    23. });
    24. });
    25. script>
    26. head>
    27. <body>
    28. <div id="header">
    29. <img class="logo_img" alt="" src="static/img/logo.gif">
    30. <span class="wel_word">网上书城span>
    31. <div>
    32. <c:if test="${empty sessionScope.user}">
    33. <a href="pages/user/login.jsp">登录a> |
    34. <a href="pages/user/regist.jsp">注册a>
    35. c:if>
    36. <c:if test="${not empty sessionScope.user}">
    37. <span>欢迎<span class="um_span">${sessionScope.user.username}span>光临尚硅谷书城span>
    38. <a href="orderServlet?action=showMyOrders&userId=${sessionScope.user.id}">我的订单a>
    39. <a href="userServlet?action=logout">注销a>
    40. c:if>  
    41. <a href="pages/cart/cart.jsp">购物车a>
    42. <a href="pages/manager/manager.jsp">后台管理a>
    43. div>
    44. div>
    45. <div id="main">
    46. <div id="book">
    47. <div class="book_cond">
    48. <form action="client/bookServlet" method="get">
    49. <input type="hidden" name="action" value="pageByPrice"/>
    50. 价格:<input id="min" type="text" name="min" value="${param.min}"> 元 -
    51. <input id="max" type="text" name="max" value="${param.max}">
    52. <input type="submit" value="查询"/>
    53. form>
    54. div>
    55. <c:if test="${empty sessionScope.cart.items}">
    56. <div style="text-align: center">
    57. <span class="totalCount"> span>
    58. <div>
    59. <span class="lastName" style="color: red">您当前的购物车里没有商品哦span>
    60. div>
    61. div>
    62. c:if>
    63. <c:if test="${not empty sessionScope.cart.items}">
    64. <div style="text-align: center">
    65. <span class="totalCount">您的购物车中有${sessionScope.cart.totalCount}件商品span>
    66. <div>
    67. 您刚刚将<span class="lastName" style="color: red">${sessionScope.lastName}span>加入到了购物车中
    68. div>
    69. div>
    70. c:if>
    71. <%-- 书籍的开始 --%>
    72. <c:forEach items="${requestScope.page.items}" var="book">
    73. <div class="b_list">
    74. <div class="img_div">
    75. <img class="book_img" alt="" src="${book.img_path}"/>
    76. div>
    77. <div class="book_info">
    78. <div class="book_name">
    79. <span class="sp1">书名:span>
    80. <span class="sp2">${book.name}span>
    81. div>
    82. <div class="book_author">
    83. <span class="sp1">作者:span>
    84. <span class="sp2">${book.author}span>
    85. div>
    86. <div class="book_price">
    87. <span class="sp1">价格:span>
    88. <span class="sp2">¥${book.price}span>
    89. div>
    90. <div class="book_sales">
    91. <span class="sp1">销量:span>
    92. <span class="sp2">${book.sales}span>
    93. div>
    94. <div class="book_amount">
    95. <span class="sp1">库存:span>
    96. <span class="sp2">${book.stock}span>
    97. div>
    98. <div class="book_add">
    99. <button bookId="${book.id}" class="addToCart">加入购物车button>
    100. div>
    101. div>
    102. div>
    103. c:forEach>
    104. <%-- 书籍的结束 --%>
    105. div>
    106. <%-- 分页条的开始 --%>
    107. <%@include file="/pages/common/nav.jsp" %>
    108. <%-- 分页条的结束 --%>
    109. div>
    110. <%@include file="/pages/common/footer.jsp" %>
    111. body>
    112. html>

  • 相关阅读:
    大学毕业设计的益处:培养实践能力、深入专业领域、展示自信与建立联系
    mysql 之进阶查询语句
    Baklib|如何为你的营销计划制作Wiki页面
    剑指 Offer 19. 正则表达式匹配
    Nacos 使用
    Redis事务的理解与使用
    Java实习生常规技术面试题每日十题Java基础(五)
    利用编码特长,我赚取了每月1000美元的额外收入
    Fundamentals of Electrostatic Discharge-INTERNATIONAL STANDARDS
    logback--进阶--01--介绍
  • 原文地址:https://blog.csdn.net/weixin_65637841/article/details/125960185