IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> JavaWeb书城项目(尚硅谷视频整理自用) -> 正文阅读

[JavaScript知识库]JavaWeb书城项目(尚硅谷视频整理自用)

作者:token comment

关于图片失效的问题,后面题主尽量重新填坑,因为我也忘了那些地方都是些什么图

第一阶段:表单验证

1、新建一个模块

2、把书城的静态资源拷贝到bookStore工程下

3、登录注册页面表单验证

在用户登录注册页面对输入数据进行一些规则限制

<!DOCTYPE html>
<html>
<head>
	<meta charset="UTF-8">
	<title>尚硅谷会员注册页面</title>
	<link href="../../static/css/style.css" type="text/css" rel="stylesheet">
	<script type="text/javascript" src="../../static/script/jquery-1.7.2.js"></script>
	<script type="text/javascript">
			// 页面加载完成之后
			$(function () {
				//给注册绑定单击事件
				$("#sub_btn").click(function () {
					//验证用户名:必须由字母数字下划线组成,并且长度为5到12位
					var username = $("#username").val();
					var patt = /^[0-9a-zA-Z_-]{5,12}$/;
					if(!patt.test(username)){
						$("span.errorMsg").text("用户名不合法!");
						return false;
					}
					//验证密码:必须由字母数字下划线组成,并且长度为5到12位
					var passtext = $("#password").val();
					var patt = /^\w{5,12}$/;
					if(!patt.test(passtext)){
						$("span.errorMsg").text("请重新输入密码!");
						return false;
					}
					//验证确认密码:和密码相同
					var pwd = $("#repwd").val();
					if(passtext != pwd){
						$("span.errorMsg").text("两次密码输入不一致!");
						return false;
					}
					//邮箱验证:xxxxx@xxx.com
					var emitext = $("#email").val();
					var emailpatt = /^([a-z0-9_\.-]+)@([\da-z\.-]+)\.([a-z\.]{2,6})$/
					if(!emailpatt.test(emitext)){
						$("span.errorMsg").text("您的邮箱格式有误!");
						return false;
					}
					//验证码:现在只需要验证用户已输入。
					var codetext = $("#code").val();
					codetext = $.trim(codetext);
					if(codetext == null || codetext == ""){
						$("span.errorMsg").text("请输入验证码!");
						return false;
					}
					$("span.errorMsg").text();
					return  false;
				});
			});
	</script>
	<style type="text/css">
		.login_form{
			height:420px;
			margin-top: 25px;
		}
	</style>
	</head>
	<body>
		<div id="login_header">
			<img class="logo_img" alt="" src="../../static/img/logo.gif" >
		</div>

			<div class="login_banner">

				<div id="l_content">
					<span class="login_word">欢迎注册</span>
				</div>

				<div id="content">
					<div class="login_form">
						<div class="login_box">
							<div class="tit">
								<h1>注册尚硅谷会员</h1>
								<span class="errorMsg"></span>
							</div>
							<div class="form">
								<form action="userServlet" method="post">
									<input type="hidden" name="action" value="regist">
									<label>用户名称:</label>
									<input class="itxt" type="text" placeholder="请输入用户名"
										   autocomplete="off" tabindex="1" name="username" id="username" />
									<br />
									<br />
									<label>用户密码:</label>
									<input class="itxt" type="password" placeholder="请输入密码"
										   autocomplete="off" tabindex="1" name="password" id="password" />
									<br />
									<br />
									<label>确认密码:</label>
									<input class="itxt" type="password" placeholder="确认密码"
										   autocomplete="off" tabindex="1" name="repwd" id="repwd" />
									<br />
									<br />
									<label>电子邮件:</label>
									<input class="itxt" type="text" placeholder="请输入邮箱地址"
										   autocomplete="off" tabindex="1" name="email" id="email" />
									<br />
									<br />
									<label>验证码:</label>
									<input class="itxt" type="text" name="code" style="width: 150px;" id="code" />
									<img alt="" src="../../static/img/code.bmp" style="float: right; margin-right: 40px">
									<br />
									<br />
									<input type="submit" value="注册" id="sub_btn" />
								</form>
							</div>

						</div>
					</div>
				</div>
			</div>

	</body>
</html>

第二阶段:用户登录注册

1、JavaEE三层架构

  • Web层/视图展现层
    • 获取请求参数,封装成Bean对象
    • 调用Service业务层处理业务
    • 响应数据给客户端请求转发、重定向
    • Servlet程序,Webwork,Strtus1.x,Strtus2.x,SpringMVC
  • Service业务层
    • 处理业务逻辑
    • 调用持久层保存到数据库
    • Spring框架
  • Dao持久层
    • Dao持久层,只负责跟数据库交互
    • 执行CRUD操作
      • Create 添加
      • Read 读/查
      • Update 修改
      • Delete 删除
    • JDBC,DbUtils,JdbcTemplate,Mybatis,Hiberante,JPA

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tTETvfQX-1647832234568)(file:///C:/Users/ZHANGY~1/AppData/Local/Temp/企业微信截图_1638522597892.png)]

分层的目的是为了降低代码耦合度,方便日后项目的维护和升级

搭建书城项目开发环境:

web层 com.company.web/servlet/controller

service层 com.company.service Service接口包

? com.company.service.impl Service接口实现类

dao层 com.company.dao Dao接口包

? com.company.dao.impl Dao接口实现类

实体类对象 com.company.bean/pojo/entity/domain JavaBean类

测试包 com.company.test/junit

工具类 com.company.utils

2、创建书城需要的数据库和表

drop database if exists book;

create database  book;
use book;

create table t_user(
    `id` int primary key  auto_increment,
    `username` varchar(20) not null unique,
    `password` varchar(32) not null ,
    `email` varchar(200)
);

insert into t_user(`username`,`password`,`email`) values('admin','admin','admin@company');

3、编写数据库对应的JavaBean对象

package com.yitong.bean;

/**
 * ClassName: User
 * Description:
 * date: 2021/12/6 9:56
 *
 * @author zhangyingying
 * @since JDK 1.8
 */
public class User {
    private int id;
    private String username;
    private String password;
    private String email;

    public User() {
    }

    public User(int id, String username, String password, String email) {
        this.id = id;
        this.username = username;
        this.password = password;
        this.email = email;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", email='" + email + '\'' +
                '}';
    }
}

4、编写工具类JdbcUtils

package com.yitong.utils;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidDataSourceFactory;

import java.io.InputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;

/**
 * ClassName: JdbcUtils
 * Description:
 * date: 2021/12/6 10:01
 *
 * @author zhangyingying
 * @since JDK 1.8
 */
public class JdbcUtils {
    //使用德鲁伊提供的数据库连接池获取连接
    private static DruidDataSource dataSource;
    //加载创建数据库连接池
    static {
        try {
            //新建配置文件对象
            Properties properties = new Properties();
            //读取jdbc.properties配置文件
            InputStream inputStream = JdbcUtils.class.getClassLoader().getResourceAsStream("jdbc.properties");
            //从流中加载数据到Properties对象中
            properties.load(inputStream);
            //创建数据库连接池(使用德鲁伊提供的数据库连接池工厂,创建数据库连接池)
            dataSource = (DruidDataSource) DruidDataSourceFactory.createDataSource(properties);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /*获取数据库连接池中的连接*/
    public static Connection getConnection(){
        Connection conn = null;
        try {
            //通过数据库连接池,获取数据库连接
            conn = dataSource.getConnection();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        //返回连接
        return conn;
    }

    /*关闭连接,放回数据库连接池*/
    public static void close(Connection conn){
        if (conn != null){
            try {
                conn.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

5、编写Base Dao类

package com.yitong.dao;

import com.yitong.utils.JdbcUtils;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanHandler;
import org.apache.commons.dbutils.handlers.BeanListHandler;
import org.apache.commons.dbutils.handlers.ScalarHandler;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;

/**
 * ClassName: BaseDao
 * Description:
 * date: 2021/12/6 14:55
 *
 * @author zhangyingying
 * @since JDK 1.8
 */

//抽象类
public abstract class BaseDao {

    //使用apache提供的DbUtils操作数据库
    private QueryRunner queryRunner = new QueryRunner();

    /**
    * @Description: update()方法用来执行:Insert/update/Delete语句
    * @author: zhangyingying
    * @date: 2021/12/6 15:10
    * @return :如果返回-1,说明执行失败,返回其他表示影响的行数
    */
    //这里没有考虑事务问题
    public int update(String sql,Object ... args){
        //连接数据库
        Connection connection = JdbcUtils.getConnection();
        try {
            //使用dbutils提供的通用更新方法更新
            int update = queryRunner.update(connection, sql, args);
            return update;
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            //关闭连接
            JdbcUtils.close(connection);
        }
        return -1;
    }

    /**
    * @Description:查询一条数据返回值,BeanHandler
    * @author: zhangyingying
    * @date: 2021/12/6 16:18
    * @param: * @Param: type
    * @Param: sql
    * @Param: args
    * @return:T
    */
    public <T> T queryForOne(Class<T> type,String sql,Object ... args){
        Connection connection = JdbcUtils.getConnection();
        try {
            T query = queryRunner.query(connection, sql, new BeanHandler<T>(type), args);
            return query;
        } catch (SQLException e) {
            e.printStackTrace();
        }finally{
            JdbcUtils.close(connection);
        }
        return null;
    }


    /**
    * @Description:查询多条数据返回值,BeanListHandler
    * @author: zhangyingying
    * @date: 2021/12/6 16:18
    * @param: * @Param: type
    * @Param: sql
    * @Param: args
    * @return:java.util.List<T>
    */
    //Class<T> type,用于接收对象.class类型。因为不确定传过来的对象类型,因此用泛型T来表示
    public <T> List<T> queryForList(Class<T> type,String sql,Object ... args){
        Connection connection = JdbcUtils.getConnection();
        try {
            //new BeanListHandler<T>(type)通过反射机制获取对象类型
            List<T> query = queryRunner.query(connection, sql, new BeanListHandler<T>(type), args);
            return query;
        } catch (SQLException e) {
            e.printStackTrace();
        }finally{
            JdbcUtils.close(connection);
        }
        return null;
    }

    /*
    * @Description:返回一行一列的sql语句
    * @author: zhangyingying
    * @date: 2021/12/6 17:34
    * @param:
    * @Param: sql执行的SQL语句
    * @Param: arg   sql对应的参数值
    * @return:java.lang.Object
    */
    public Object queryForSingleValue(String sql,Object ... arg){
        Connection connection = JdbcUtils.getConnection();
        try {
            Object query = queryRunner.query(connection, sql, new ScalarHandler(), arg);
            return query;
        } catch (SQLException e) {
            e.printStackTrace();
        }finally {
            JdbcUtils.close(connection);
        }
        return null;
    }
}

6、编写UserDao接口类、实现类和测试类

UserDao的接口类

package com.yitong.dao;

import com.yitong.bean.User;

/**
 * ClassName: UserDao
 * Description:
 * date: 2021/12/7 11:08
 *
 * @author zhangyingying
 * @since JDK 1.8
 */
public interface UserDao {

    //根据用户名查用户信息,如果返回null说明没有这个用户,反之亦然
    //用于注册时查找用户名是否被使用
    public User queryUserByUsername(String username);

    //根据用户名和密码查用户信息,返回null说明没有这个用户
    //用于登录时核对用户信息
    public User queryUserByUsernameAndPassword(String username,String password);

    //保存用户信息,返回-1表示操作失败
    public int saveUser(User user);
}

UserDao实现类

package com.yitong.dao.impl;

import com.yitong.bean.User;
import com.yitong.dao.BaseDao;
import com.yitong.dao.UserDao;


/**
 * ClassName: UserDaoImpl
 * Description:
 * date: 2021/12/7 11:16
 *
 * @author zhangyingying
 * @since JDK 1.8
 */
//继承BaseDao才能使用BaseDao中的方法
public class UserDaoImpl extends BaseDao implements UserDao {
    @Override
    public User queryUserByUsername(String username) {
        String sql = "select * from t_user where username = ?";
        User user = queryForOne(User.class, sql, username);
        return user;
    }

    @Override
    public User queryUserByUsernameAndPassword(String username, String password) {
        String sql = "select * from t_user where username = ? and password = ?";
        User user = queryForOne(User.class, sql, username,password);
        return user;
    }

    @Override
    public int saveUser(User user) {
        String sql = "insert into t_user (`username`,`password`,`email`) values (?,?,?)";
        int update = update(sql, user.getUsername(), user.getPassword(), user.getEmail());
        return update;
    }
}

UserDao的测试类

package com.yitong.test;

import com.yitong.bean.User;
import com.yitong.dao.UserDao;
import com.yitong.dao.impl.UserDaoImpl;
import org.junit.Test;

/**
 * ClassName: UserDaoTest
 * Description:
 * date: 2021/12/7 11:28
 *
 * @author zhangyingying
 * @since JDK 1.8
 */

public class UserDaoTest {
    //实现类可以由对应的接口类接收
    UserDao userDao = new UserDaoImpl();
    @Test
    public void UserDaoTest(){

        String username = "admin";
        User user1 = userDao.queryUserByUsername(username);
        if (user1 == null) {
            System.out.println("该用户不存在!");
        }else{
            System.out.println(user1);
        }


        String name = "root";
        String password = "root";
        User user2 = userDao.queryUserByUsernameAndPassword(name,password);
        if (user2 == null) {
            System.out.println("该用户不存在");
        }else{
            System.out.println(user2);
        }
        
        //这里的username不能和数据库里的重复
        User user = new User("zhangsan","123456","root@qq.com");
        int i = userDao.saveUser(user);
        System.out.println(i);
    }
}

7、编写UserService接口类实现类和测试类

UserService接口类

package com.yitong.service;

import com.yitong.bean.User;

/**
 * ClassName: UserService业务层
 * Description:
 * date: 2021/12/7 14:37
 *
 * @author zhangyingying
 * @since JDK 1.8
 */
public interface UserService {
    //注册新用户
    public void registerUser(User user);

    //登录,如果返回null是登录失败,返回有值表示登录成功。
    public User login(User user);

    //检查用户名是否可用,返回true表示用户名已存在,返回false表示用户名可用
    public boolean existUsername(String username);
}

UserServiceImpl接口实现类

package com.yitong.service.impl;

import com.yitong.bean.User;
import com.yitong.dao.UserDao;
import com.yitong.dao.impl.UserDaoImpl;
import com.yitong.service.UserService;

/**
 * ClassName: UserSeviceImpl
 * Description:
 * date: 2021/12/7 14:37
 *
 * @author zhangyingying
 * @since JDK 1.8
 */
public class UserServiceImpl implements UserService {
    //需要操作数据库就需要使用到Dao层的一些类方法。
    private UserDao userDao = new UserDaoImpl();

    //注册
    @Override
    public void registerUser(User user) {
       userDao.saveUser(user);
    }

    //登录
    @Override
    public User login(User user) {

        return userDao.queryUserByUsernameAndPassword(user.getUsername(),user.getPassword());
    }

    @Override
    public boolean existUsername(String username) {
        User user = userDao.queryUserByUsername(username);
        if(user == null){
            //如果等于null,说明没查到,表示用户名可用
            return false;
        }
        return true;
    }
}

service层测试类

package com.yitong.test;

import com.yitong.bean.User;
import com.yitong.service.UserService;
import com.yitong.service.impl.UserServiceImpl;
import org.junit.Test;

/**
 * ClassName: UserServiceTest
 * Description:
 * date: 2021/12/7 15:13
 *
 * @author zhangyingying
 * @since JDK 1.8
 */
public class UserServiceTest {
    UserService userService = new UserServiceImpl();

    @Test
    public void registerUser(){
        userService.registerUser(new User("zhouqi","lisi","lisi@qq.com"));
    }

    @Test
    public void login( ) {
        userService.login(new User("root","root",null));
    }

    @Test
    public void existUsername(){
        userService.existUsername("lisi");
    }
}

8、实现用户的注册功能

项目第二阶段:用户注册和登录的实现。

需求1:用户注册:当用户输入完成,就会点击提交,把参数都发送给服务器,去注册保存。

  1. 获取请求参数
  2. 检查验证码是否正确
    • 正确
      • 检查用户名是否可用
        • 可用
          • 调用Service层保存到数据库
          • 跳到注册成功页面
        • 不可用
          • 跳回注册页面
    • 不正确
      • 跳回注册页面

? 功能需求

? 访问注册页面

? 填写注册信息,提交给服务器

? 服务器应该保存用户注册失败,用户名已存在

? 当用户不存在,注册成功

RegisteServlet

package com.yitong.controller;

import com.yitong.bean.User;
import com.yitong.service.UserService;
import com.yitong.service.impl.UserServiceImpl;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * ClassName: RegistServlet
 * Description:
 * date: 2021/12/7 16:22
 * @author zhangyingying
 * @since JDK 1.8
 */
public class RegistServlet extends HttpServlet {
    private UserService  userService = new UserServiceImpl();
    /*
    * @Description: 密码不能被人看见因此使用doPost
    * @author: zhangyingying
    * @date: 2021/12/8 11:54
    * @Param: req
    * @Param: resp
    * @return:void
    */
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//        1. 获取请求参数
        //用户名
        String username = req.getParameter("username");
        //密码
        String password = req.getParameter("password");
        //邮箱
        String email = req.getParameter("email");
        //验证码
        String code = req.getParameter("code");
//        2. 检查验证码是否正确========要求验证码为abcde
        if("abcde".equalsIgnoreCase(code)){
//           正确
//             检查用户名是否可用
            if(userService.existUsername(username)){
//               不可用
                System.out.println("用户名:" + username + "不可用");
//                 跳回注册页面
                req.getRequestDispatcher("/pages/user/regist.html").forward(req,resp);
            }else{
//               可用
//                 调用Service层保存到数据库
//                 跳到注册成功页面
                userService.registerUser(new User(username,password,email));
                req.getRequestDispatcher("/pages/user/regist_success.html").forward(req,resp);
            }

        }else{
//            不正确
//              跳回注册页面
            System.out.println("验证码[" + code + "]错误");
            req.getRequestDispatcher("/pages/user/regist.html").forward(req,resp);
        }
    }
}

9、IDEA中Debug调试的使用

9.1、Debug调试

Debug调试代码,首先两个元素:断电+Debug启动服务器

  • 断点,是需要在代码需要停止的行的左边上单击,就可以添加或取消。
  • Debug启动Tomcat运行代码

9.2、调试工具栏

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nob5fzUv-1647832234569)(C:\Users\zhangyingying\AppData\Roaming\Typora\typora-user-images\image-20211208144948405.png)]

? 1 2 4 3 5 6

  1. 表示让代码往下执行一行
  2. 可以进入当前方法体内(自己写的代码,非框架源码)
  3. 跳出当前方法体外
  4. 强制进入当前方法体内
  5. 停在光标所在行(相当于临时断点)

9.3、变量窗口

变量窗口:可以查看当前方法范围内所有有效的变量。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Z693AQTS-1647832234570)(C:\Users\zhangyingying\AppData\Roaming\Typora\typora-user-images\image-20211208152312767.png)]

9.4、方法调用栈窗口

  1. 方法调用栈可以查看当前线程有哪些方法调用信息。
  2. 下一行调用上一行的方法

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zjsWCDTt-1647832234570)(C:\Users\zhangyingying\AppData\Roaming\Typora\typora-user-images\image-20211208152334749.png)]

9.5、其他常用调试按钮:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cswfj7xI-1647832234570)(C:\Users\zhangyingying\AppData\Roaming\Typora\typora-user-images\image-20211208151537440.png)]

第七个按钮:程序一直跑,直到下一个断点停下来。如果没有断点,就一直往下走

最后一个按钮:临时禁用所有断点

10、实现用户的登录功能

需求2:用户登录

  1. 获取请求参数
  2. 调用Xxx.Service.xxx()处理业务。
    • userService.login()登录
  3. 根据login()方法返回结果判断登录方式是否成功
    • 成功
      • 跳到成功登录页面
    • 失败
      • 跳回登录页面

? 功能需求:

? 访问登陆页面

? 填写用户名密码后提交

? 服务器判断用户是否存在

? 如果登录失败返回用户名或者密码错误信息

package com.yitong.controller;

import com.yitong.bean.User;
import com.yitong.service.UserService;
import com.yitong.service.impl.UserServiceImpl;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * ClassName: LoginServlet
 * Description:
 * date: 2021/12/8 10:29
 *
 * @author zhangyingying
 * @since JDK 1.8
 */
public class LoginServlet extends HttpServlet {

    private UserService userService = new UserServiceImpl();
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1. 获取请求参数
        String username = req.getParameter("username");
        String password = req.getParameter("password");
//2. 调用Xxx.Service.xxx()处理业务。
//          userService.login()登录
        User login = userService.login(new User(username, password, null));

//3. 根据login()方法返回结果判断登录方式是否成功
        if (login == null){
//     失败
//       跳回登录页面
            req.getRequestDispatcher("/pages/user/login.html").forward(req,resp);
        }else {
//     成功
//       跳到成功登录页面
            req.getRequestDispatcher("/pages/user/login_success.html").forward(req,resp);
        }
    }
}

第三阶段:优化

1、页面jsp动态化

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fx4nr37G-1647832234571)(file:///C:/Users/ZHANGY~1/AppData/Local/Temp/企业微信截图_16394518187103.png)]

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

2.1、head中的css、jquery、base标签

head.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%--动态获取路径信息--%>
<%
    String basePath = request.getScheme()
            + "://"
            + request.getServerName()
            + ":"
            + request.getServerPort()
            + request.getContextPath()
            + "/";
%>
<!--写base标签,永远固定相对路径跳转的结果:工程路径-->
<base href=<%=basePath%>>
<link type="text/css" rel="stylesheet" href="static/css/style.css" >
<script type="text/javascript" src="static/script/jquery-1.7.2.js"></script>

页面中静态包含

<%--静态包含base标签,css样式,jQuery文件--%>
<%@include file="/pages/common/head.jsp"%>

2.2、每个页面的页脚

footer.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<div id="bottom">
	<span>尚硅谷书城.Copyright &copy;2015</span>
</div>

页面静态包含

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

2.3、登录成功后的菜单

login_success_menu.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<div>
    <span>欢迎<span class="um_span">韩总</span>光临尚硅谷书城</span>
    <a href="../order/order.jsp">我的订单</a>
    <a href="../../index.jsp">注销</a>&nbsp;&nbsp;
    <a href="../../index.jsp">返回</a>
</div>

页面静态包含

<%--静态包含base标签,css样式,jQuery文件--%>
<%@include file="/pages/common/head.jsp"%>

2.4、manager模块的菜单

manager_menu.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<div>
    <a href="book_manager.jsp">图书管理</a>
    <a href="order_manager.jsp">订单管理</a>
    <a href="../../index.jsp">返回商城</a>
</div>

页面静态包含

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

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-cMj5S0zh-1647832234571)(file:///C:/Users/ZHANGY~1/AppData/Local/Temp/企业微信截图_16394628072267.png)]

Servlet程序端添加回显信息显示到request域中,以注册为例

注册servlet

        if("abcde".equalsIgnoreCase(code)){
//           正确
//             检查用户名是否可用
            if(userService.existUsername(username)){
                //把回显信息保存到request域中
                req.setAttribute("msg","用户名已存在!");
                req.setAttribute("username",username);
                req.setAttribute("email",email);
//               不可用
                System.out.println("用户名:" + username + "不可用");
//                 跳回注册页面
                req.getRequestDispatcher("/pages/user/regist.jsp").forward(req,resp);
            }else{
//               可用
//                 调用Service层保存到数据库
//                 跳到注册成功页面
                userService.registerUser(new User(username,password,email));
                req.getRequestDispatcher("/pages/user/regist_success.jsp").forward(req,resp);
            }

        }else{
//            不正确
            //把回显信息保存到request域中
            req.setAttribute("msg","验证码错误!");
            req.setAttribute("username",username);
            req.setAttribute("email",email);
//              跳回注册页面
            System.out.println("验证码[" + code + "]错误");
            req.getRequestDispatcher("/pages/user/regist.jsp").forward(req,resp);
        }

注册信息页面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html>
   <head>
      <meta charset="UTF-8">
      <title>尚硅谷会员注册页面</title>
      <%--静态包含base标签,css样式,jQuery文件--%>
      <%@include file="/pages/common/head.jsp"%>
      <script type="text/javascript">
         // 页面加载完成之后
         $(function () {
            // 给注册绑定单击事件
            $("#sub_btn").click(function () {
               // 验证用户名:必须由字母,数字下划线组成,并且长度为5到12位
               //1 获取用户名输入框里的内容
               var usernameText = $("#username").val();
               //2 创建正则表达式对象
               var usernamePatt = /^\w{5,12}$/;
               //3 使用test方法验证
               if (!usernamePatt.test(usernameText)) {
                  //4 提示用户结果
                  $("span.errorMsg").text("用户名不合法!");

                  return false;
               }

               // 验证密码:必须由字母,数字下划线组成,并且长度为5到12位
               //1 获取用户名输入框里的内容
               var passwordText = $("#password").val();
               //2 创建正则表达式对象
               var passwordPatt = /^\w{5,12}$/;
               //3 使用test方法验证
               if (!passwordPatt.test(passwordText)) {
                  //4 提示用户结果
                  $("span.errorMsg").text("密码不合法!");

                  return false;
               }

               // 验证确认密码:和密码相同
               //1 获取确认密码内容
               var repwdText = $("#repwd").val();
               //2 和密码相比较
               if (repwdText != passwordText) {
                  //3 提示用户
                  $("span.errorMsg").text("确认密码和密码不一致!");

                  return false;
               }

               // 邮箱验证:xxxxx@xxx.com
               //1 获取邮箱里的内容
               var emailText = $("#email").val();
               //2 创建正则表达式对象
               var emailPatt = /^[a-z\d]+(\.[a-z\d]+)*@([\da-z](-[\da-z])?)+(\.{1,2}[a-z]+)+$/;
               //3 使用test方法验证是否合法
               if (!emailPatt.test(emailText)) {
                  //4 提示用户
                  $("span.errorMsg").text("邮箱格式不合法!");

                  return false;
               }

               // 验证码:现在只需要验证用户已输入。因为还没讲到服务器。验证码生成。
               var codeText = $("#code").val();

               //去掉验证码前后空格
               // alert("去空格前:["+codeText+"]")
               codeText = $.trim(codeText);
               // alert("去空格后:["+codeText+"]")

               if (codeText == null || codeText == "") {
                  //4 提示用户
                  $("span.errorMsg").text("验证码不能为空!");

                  return false;
               }

               // 去掉错误信息
               $("span.errorMsg").text("");

            });

         });

      </script>
   <style type="text/css">
      .login_form{
         height:420px;
         margin-top: 25px;
      }

   </style>
   </head>
   <body>
      <div id="login_header">
         <img class="logo_img" alt="" src="static/img/logo.gif" >
      </div>

         <div class="login_banner">

            <div id="l_content">
               <span class="login_word">欢迎注册</span>
            </div>

            <div id="content">
               <div class="login_form">
                  <div class="login_box">
                     <div class="tit">
                        <h1>注册尚硅谷会员</h1>
                        <span class="errorMsg">
                           <%=request.getAttribute("msg")==null?"":request.getAttribute("msg")%>
                        </span>
                     </div>
                     <div class="form">
                        <form action="registServlet" method="post">
                           <label>用户名称:</label>
                           <input class="itxt" type="text" placeholder="请输入用户名"
                                 value="<%=request.getAttribute("username")==null?"":request.getAttribute("username")%>"
                                 autocomplete="off" tabindex="1" name="username" id="username" />
                           <br />
                           <br />
                           <label>用户密码:</label>
                           <input class="itxt" type="password" placeholder="请输入密码"
                                 autocomplete="off" tabindex="1" name="password" id="password" />
                           <br />
                           <br />
                           <label>确认密码:</label>
                           <input class="itxt" type="password" placeholder="确认密码"
                                 autocomplete="off" tabindex="1" name="repwd" id="repwd" />
                           <br />
                           <br />
                           <label>电子邮件:</label>
                           <input class="itxt" type="text" placeholder="请输入邮箱地址"
                                 value="<%=request.getAttribute("email")==null?"":request.getAttribute("email")%>"
                                 autocomplete="off" tabindex="1" name="email" id="email" />
                           <br />
                           <br />
                           <label>验证码:</label>
                           <input class="itxt" type="text" name="code" style="width: 150px;" id="code" value="abcde"/>
                           <img alt="" src="static/img/code.bmp" style="float: right; margin-right: 40px">
                           <br />
                           <br />
                           <input type="submit" value="注册" id="sub_btn" />
                        </form>
                     </div>

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

4、优化代码

4.1、合并LoginServlet和RegistServlet程序为UserServlet

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

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uBnrZkKE-1647832234571)(file:///C:/Users/ZHANGY~1/AppData/Local/Temp/企业微信截图_16394656534980.png)]

package com.yitong.controller;

import com.yitong.bean.User;
import com.yitong.service.UserService;
import com.yitong.service.impl.UserServiceImpl;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class UserServlet extends HttpServlet {
    private UserService userService = new UserServiceImpl();

    protected void regist(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        //1. 获取请求参数
        //用户名
        String username = req.getParameter("username");
        //密码
        String password = req.getParameter("password");
        //邮箱
        String email = req.getParameter("email");
        //验证码
        String code = req.getParameter("code");
        //2. 检查验证码是否正确========要求验证码为abcde
        if("abcde".equalsIgnoreCase(code)){
            //正确
            //检查用户名是否可用
            if(userService.existUsername(username)){
                //把回显信息保存到request域中
                req.setAttribute("msg","用户名已存在!");
                req.setAttribute("username",username);
                req.setAttribute("email",email);
                //不可用
                System.out.println("用户名:" + username + "不可用");
                //跳回注册页面
                req.getRequestDispatcher("/pages/user/regist.jsp").forward(req,resp);
            }else{
                //可用
                //调用Service层保存到数据库
                //跳到注册成功页面
                userService.registerUser(new User(username,password,email));
                req.getRequestDispatcher("/pages/user/regist_success.jsp").forward(req,resp);
            }

        }else{
        //不正确
            //把回显信息保存到request域中
            req.setAttribute("msg","验证码错误!");
            req.setAttribute("username",username);
            req.setAttribute("email",email);
            //跳回注册页面
            System.out.println("验证码[" + code + "]错误");
            req.getRequestDispatcher("/pages/user/regist.jsp").forward(req,resp);
        }
    }
    
    protected void login(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //1. 获取请求参数
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        //2. 调用Xxx.Service.xxx()处理业务。
        //userService.login()登录
        User login = userService.login(new User(username, password, null));

        //3. 根据login()方法返回结果判断登录方式是否成功
        if (login == null){
        //失败
            //把错误信息和回显的表单项信息保存到Request域中
            req.setAttribute("msg","用户名或密码错误!");
            req.setAttribute("username",username);
        //跳回登录页面
            req.getRequestDispatcher("/pages/user/login.jsp").forward(req,resp);
        }else {
            //成功
            //跳到成功登录页面
            req.getRequestDispatcher("/pages/user/login_success.jsp").forward(req,resp);
        }
    }
    
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String action = req.getParameter("action");
        if ("regist".equals(action)){
            regist(req,resp);
        }else if ("login".equals(action)){
            login(req,resp);
        }
    }
}

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

<form action="userServlet" method="post">
	<input type="hidden" name="action" value="login"/>
<form action="userServlet" method="post">
    <input type="hidden" name="action" value="regist"/>

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

实际项目中一个模块可能会有很对功能,每一个功能都在doPost中用else if判断再执行相应的方法回造成else if代码大量冗余。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-T6a96hEw-1647832234571)(file:///C:/Users/ZHANGY~1/AppData/Local/Temp/企业微信截图_16394665424892.png)]

因此我们通过使用反射获取要执行的对应的方法对其进行执行。不用再大量的写else if语句判断。

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

4.3、抽取BaseServlet程序

由于所有的Servlet都需要进行相同的反射操作调用相应的方法执行,所以将doPost抽取出来写成BaseServlet类,需要实现反射调用的类继承BaseServlet就可以完成代码的精简。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-chrsy2fZ-1647832234572)(file:///C:/Users/ZHANGY~1/AppData/Local/Temp/企业微信截图_16394694498391.png)]

package com.yitong.controller;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Method;

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

从此只需要继承BaseServlet而无需继承HttpServlet

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

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

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

BeanUtils它不是JDK的类,而是一种第三方工具类。所以需要导包。

  1. 导入需要的jar包

    commons-beanutils-1.8.0.jar

    commons-logging-1.1.1.jar

  2. 使用BeanUtils类方法实现注入

    ? 通过属性名和参数名对应的关系实现注入的,属性名是实体类中的定义的属性。参数名是表单中对应的name值。但注入找的是set方法,一旦set方法中的属性名和参数名不对应,尽管属性名和参数名相同,还是会注入失败。

    BeanUtils.populate(bean,request.getParameterMap());
    
  3. 编写WebUtil工具类使用

   package com.yitong.utils;
   
   import com.yitong.bean.User;
   import org.apache.commons.beanutils.BeanUtils;
   
   import javax.servlet.http.HttpServletRequest;
   import java.lang.reflect.InvocationTargetException;
   import java.util.Map;
   
   public class WebUtils {
       //把Map值注入到对应的JavaBean属性中,这样写适用范围更广,耦合度更低,扩展性更强,使用更加灵活。
       public static void copyParamToBean(HttpServletRequest req, Object bean){
           try {
               System.out.println("注入之前" + bean);
   
               BeanUtils.populate(bean,req.getParameterMap());
               System.out.println("注入之后" + bean);
           } catch (Exception e) {
               e.printStackTrace();
           }
       }
   }

调用

WebUtils.copyParamToBean(request,user);

? 我们将Map的值注入到JavaBean中是很常见的。

java代码分为三层,dao层,Service层,servlet层。如果将参数写为HttpServletRequest req,Dao层和Service层没有这个API,不能使用这个方法,带来了Servlet层API的耦合度高。但是写成Map在三层都能使用这个方法

package com.yitong.utils;

import com.yitong.bean.User;
import org.apache.commons.beanutils.BeanUtils;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.InvocationTargetException;
import java.util.Map;

public class WebUtils {
 //把Map值注入到对应的JavaBean属性中,这样写适用范围更广,耦合度更低,扩展性更强,使用更加灵活。
 public static void copyParamToBean(Map value, Object bean){
     try {
         System.out.println("注入之前" + bean);

         BeanUtils.populate(bean,value);
         System.out.println("注入之后" + bean);
     } catch (Exception e) {
         e.printStackTrace();
     }
 }
}

调用时

WebUtils.copyParamToBean(req.getParameterMap(),user);

优化

package com.yitong.utils;

import com.yitong.bean.User;
import org.apache.commons.beanutils.BeanUtils;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.InvocationTargetException;
import java.util.Map;

public class WebUtils {
 public static Object copyParamToBean(Map value, Object bean){
     try {
         System.out.println("注入之前" + bean);
         BeanUtils.populate(bean,value);
         System.out.println("注入之后" + bean);
     } catch (Exception e) {
         e.printStackTrace();
     }
     return bean;
 }
}

User user = (User) WebUtils.copyParamToBean(req.getParameterMap(), new User());

再优化

package com.yitong.utils;

import com.yitong.bean.User;
import org.apache.commons.beanutils.BeanUtils;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.InvocationTargetException;
import java.util.Map;


public class WebUtils {
 public static <T> T copyParamToBean(Map value, T bean){
     try {
         System.out.println("注入之前" + bean);

         BeanUtils.populate(bean,value);
         System.out.println("注入之后" + bean);
     } catch (Exception e) {
         e.printStackTrace();
     }
     return bean;
 }
}
User user = WebUtils.copyParamToBean(req.getParameterMap(), new User());

第四阶段:使用EL表达式修改表单回显

login.jsp

EL表达式null就是空串,所以空串可以不用判断,我们将表达式改为EL表达式

<span class="errorMsg">
    <%--<%=request.getAttribute("msg")==null?"请输入用户名和密码":request.getAttribute("msg")%>--%>
    ${empty requestScope.msg ? "请输入用户名和密码":requestScope.msg}
</span>
    
    
<input class="itxt" type="text" placeholder="请输入用户名"
    autocomplete="off" tabindex="1" name="username"
    <%--value="<%=request.getAttribute("username")==null?"":request.getAttribute("username")%>"--%>
    value="${requestScope.username}"/>    

regist.jsp

<span class="errorMsg">
    <%--<%=request.getAttribute("msg")==null?"":request.getAttribute("msg")%>--%>
    ${requestScope.msg}
</span>
<input class="itxt" type="text" placeholder="请输入用户名"
       <%--value="<%=request.getAttribute("username")==null?"":request.getAttribute("username")%>"--%>
       value="${ requestScope.username}"
       autocomplete="off" tabindex="1" name="username" id="username" />
<input class="itxt" type="text" placeholder="请输入邮箱地址"
       <%--value="<%=request.getAttribute("email")==null?"":request.getAttribute("email")%>"--%>
       value="${requestScope.email}"
       autocomplete="off" tabindex="1" name="email" id="email" />

第五阶段:图书模块

1、MVC概念

  • MVC全称:Model模型、View视图、Controller控制器
  • MVC最早出现再JavaEE三层中的web层,它可以有效的指导Web层的代码如何有效分离,单独工作。
  • View视图:只负责数据和界面的显示,不接受任何与显示数据无关的代码,便于程序员和美工的分工合作——JSP/HTML
  • Controller控制器:只负责接收请求,调用业务层的代码处理请求,然后派发页面,是一个“调度者”的角色——Servlet。
  • Model:将与业务逻辑相关的数据封装为具体JavaBean类,其中不掺杂任何与数据处理相关的代码——JavaBean/domain/entity/pojo

MVC是一种思想

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

让各层的代码尽可能的独立工作,而不产生依赖,方便后期升级和维护。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EihtKy8K-1647832234572)(file:///C:/Users/ZHANGY~1/AppData/Local/Temp/企业微信截图_16395317789938.png)]

2、图书模块

2.1、编写图书模块的数据库表

#创建图书模块表
create table t_book(
  `id` int primary key auto_increment,
  `name` varchar(100),
  `price` decimal(11,2),
  `author` varchar(100),
  `sales` int,
  `stock` int,
  `img_path` varchar(200)
);
#插入数据
insert into t_book(`id` , `name` , `author` , `price` , `sales` , `stock` , `img_path`)
values(null , 'java 从入门到放弃' , '国哥' , 80 , 9999 , 9 , 'static/img/default.jpg');
insert into t_book(`id` , `name` , `author` , `price` , `sales` , `stock` , `img_path`)
values(null , '数据结构与算法' , '严敏君' , 78.5 , 6 , 13 , 'static/img/default.jpg');
insert into t_book(`id` , `name` , `author` , `price` , `sales` , `stock` , `img_path`)
values(null , '怎样拐跑别人的媳妇' , '龙伍' , 68, 99999 , 52 , 'static/img/default.jpg');
insert into t_book(`id` , `name` , `author` , `price` , `sales` , `stock` , `img_path`)
values(null , '木虚肉盖饭' , '小胖' , 16, 1000 , 50 , 'static/img/default.jpg');
insert into t_book(`id` , `name` , `author` , `price` , `sales` , `stock` , `img_path`)
values(null , 'C++编程思想' , '刚哥' , 45.5 , 14 , 95 , 'static/img/default.jpg');
insert into t_book(`id` , `name` , `author` , `price` , `sales` , `stock` , `img_path`)
values(null , '蛋炒饭' , '周星星' , 9.9, 12 , 53 , 'static/img/default.jpg');
insert into t_book(`id` , `name` , `author` , `price` , `sales` , `stock` , `img_path`)
values(null , '赌神' , '龙伍' , 66.5, 125 , 535 , 'static/img/default.jpg');
insert into t_book(`id` , `name` , `author` , `price` , `sales` , `stock` , `img_path`)
values(null , 'Java 编程思想' , '阳哥' , 99.5 , 47 , 36 , 'static/img/default.jpg');
insert into t_book(`id` , `name` , `author` , `price` , `sales` , `stock` , `img_path`)
values(null , 'JavaScript 从入门到精通' , '婷姐' , 9.9 , 85 , 95 , 'static/img/default.jpg');
insert into t_book(`id` , `name` , `author` , `price` , `sales` , `stock` , `img_path`)
values(null , 'cocos2d-x 游戏编程入门' , '国哥' , 49, 52 , 62 , 'static/img/default.jpg');
insert into t_book(`id` , `name` , `author` , `price` , `sales` , `stock` , `img_path`)
values(null , 'C 语言程序设计' , '谭浩强' , 28 , 52 , 74 , 'static/img/default.jpg');
insert into t_book(`id` , `name` , `author` , `price` , `sales` , `stock` , `img_path`)
values(null , 'Lua 语言程序设计' , '雷丰阳' , 51.5 , 48 , 82 , 'static/img/default.jpg');
insert into t_book(`id` , `name` , `author` , `price` , `sales` , `stock` , `img_path`)
values(null , '西游记' , '罗贯中' , 12, 19 , 9999 , 'static/img/default.jpg');
insert into t_book(`id` , `name` , `author` , `price` , `sales` , `stock` , `img_path`)
values(null , '水浒传' , '华仔' , 33.05 , 22 , 88 , 'static/img/default.jpg');
insert into t_book(`id` , `name` , `author` , `price` , `sales` , `stock` , `img_path`)
values(null , '操作系统原理' , '刘优' , 133.05 , 122 , 188 , 'static/img/default.jpg');
insert into t_book(`id` , `name` , `author` , `price` , `sales` , `stock` , `img_path`)
values(null , '数据结构 java 版' , '封大神' , 173.15 , 21 , 81 , 'static/img/default.jpg');
insert into t_book(`id` , `name` , `author` , `price` , `sales` , `stock` , `img_path`)
values(null , 'UNIX 高级环境编程' , '乐天' , 99.15 , 210 , 810 , 'static/img/default.jpg');
insert into t_book(`id` , `name` , `author` , `price` , `sales` , `stock` , `img_path`)
values(null , 'javaScript 高级编程' , '国哥' , 69.15 , 210 , 810 , 'static/img/default.jpg');
insert into t_book(`id` , `name` , `author` , `price` , `sales` , `stock` , `img_path`)
values(null , '大话设计模式' , '国哥' , 89.15 , 20 , 10 , 'static/img/default.jpg');
insert into t_book(`id` , `name` , `author` , `price` , `sales` , `stock` , `img_path`)
values(null , '人月神话' , '刚哥' , 88.15 , 20 , 80 , 'static/img/default.jpg');
#查看表内容
select id,name,author,price,sales,stock,img_path from t_book;

2.2、编写图书模块的JavaBean

package com.yitong.bean;

import java.math.BigDecimal;

/**
 * ClassName: Book
 * Description:
 * date: 2021/12/15 9:53
 *
 * @author zhangyingying
 * @since JDK 1.8
 */
public class Book {
    private Integer id;
    private String name;
    private String author;
    private BigDecimal price;
    private Integer sales;
    private Integer stock;
    private String imgPath="static/img/default.jpg";

    public Book() {
    }

    public Book(Integer id, String name, String author, BigDecimal price, Integer sales, Integer stock, String imgPath) {
        this.id = id;
        this.name = name;
        this.author = author;
        this.price = price;
        this.sales = sales;
        this.stock = stock;
        //要求给定的图书封面路径不能为空
        if(imgPath != null && !"".equals(imgPath)){
            this.imgPath = imgPath;
        }

    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }

    public BigDecimal getPrice() {
        return price;
    }

    public void setPrice(BigDecimal price) {
        this.price = price;
    }

    public Integer getSales() {
        return sales;
    }

    public void setSales(Integer sales) {
        this.sales = sales;
    }

    public Integer getStock() {
        return stock;
    }

    public void setStock(Integer stock) {
        this.stock = stock;
    }

    public String getImgPath() {
        return imgPath;
    }

    public void setImgPath(String imgPath) {
        //要求给定的图书封面路径不能为空
        if(imgPath != null && !"".equals(imgPath)){
            this.imgPath = imgPath;
        }
    }

    @Override
    public String toString() {
        return "Book{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", author='" + author + '\'' +
                ", price=" + price +
                ", sales=" + sales +
                ", stock=" + stock +
                ", imgPath='" + imgPath + '\'' +
                '}';
    }
}

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

BookDao接口

package com.yitong.dao;

import com.yitong.bean.Book;

import java.util.List;

/**
 * ClassName: BookDao
 * Description:
 * date: 2021/12/15 10:02
 *
 * @author zhangyingying
 * @since JDK 1.8
 */
public interface BookDao {
    //
    public int addBook(Book book);

    public int deleteBookById(int id);

    public int updateBook(Book book);

    public Book queryBookById(int id);

    public List<Book> queryBooks();
}

BookDaoImpl接口实现类

package com.yitong.dao.impl;

import com.yitong.bean.Book;
import com.yitong.dao.BookDao;

import java.math.BigDecimal;
import java.util.List;

/**
 * ClassName: BookDaoImpl
 * Description:
 * date: 2021/12/15 10:05
 *
 * @author zhangyingying
 * @since JDK 1.8
 */
public class BookDaoImpl extends BaseDao implements BookDao {

    //新增书籍
    @Override
    public int addBook(Book book) {
        String sql = "insert into t_book (`name`,`author`,`price`,`sales`,`stock`,`img_path`) values (?,?,?,?,?,?)";
        int add = update(sql, book.getName(), book.getAuthor(), book.getPrice(), book.getSales()
                , book.getStock(), book.getImgPath());
        return add;
    }

    //删除
    @Override
    public int deleteBookById(int id) {
        String sql = "delete from t_book where id = ?";
        int delete = update(sql, id);
        return delete;
    }

    //更改书籍信息
    @Override
    public int updateBook(Book book) {
        String sql = "update t_book set `name`=? ,`author`=?,`price`=?,`sales`=?,`stock`=?,`img_path`=? where id=?";
        int add = update(sql, book.getName(), book.getAuthor(), book.getPrice(), book.getSales(), book.getStock(),book.getImgPath(),book.getId());
        return add;
    }

    //根据id查书籍
    @Override
    public Book queryBookById(int id) {
        String sql="select `name`,`author`,`price`,`sales`,`stock`,`img_path` imgPath from t_book where id = ?";
        Book book = queryForOne(Book.class, sql, id);
        return book;
    }

    //查询所有书籍
    @Override
    public List<Book> queryBooks() {
        String sql="select `name`,`author`,`price`,`sales`,`stock`,`img_path` imgPath from t_book";
        List<Book> books = queryForList(Book.class, sql);
        return books;
    }
}

BookDao测试类

package com.yitong.test;

import com.yitong.bean.Book;
import com.yitong.dao.BookDao;
import com.yitong.dao.impl.BookDaoImpl;
import org.junit.Test;

import java.math.BigDecimal;
import java.util.List;

/**
 * ClassName: BookDaoTest
 * Description:
 * date: 2021/12/15 10:46
 *
 * @author zhangyingying
 * @since JDK 1.8
 */
public class BookDaoTest {
    private BookDao bookDao = new BookDaoImpl();

    @Test
    public void addBook() {
        Book book = new Book(20, "MySQL从入门到入狱", "李四", new BigDecimal(9.99), 9999, 2, "static/img/default.jpg");
        int i = bookDao.addBook(book);
        System.out.println(i);
    }

    @Test
    public void deleteBookById() {
        int i = bookDao.deleteBookById(21);
        System.out.println(i);
    }

    @Test
    public void updateBook() {
        int i = bookDao.updateBook(new Book(19, "JAVA从入门到跑路", "张三", new BigDecimal(9.99), 9999, 2, "static/img/default.jpg"));
        System.out.println(i);
    }

    @Test
    public void queryBookById() {
        Book book = bookDao.queryBookById(13);
        System.out.println(book);
    }

    @Test
    public void queryBooks() {
        List<Book> books = bookDao.queryBooks();
        for (Book book : books) {
            System.out.println(book);
        }
    }
}

2.4、编写图书模块Service和测试Service

BookService接口类

package com.yitong.service;

import com.yitong.bean.Book;

import java.util.List;

/**
 * ClassName: BookService
 * Description:
 * date: 2021/12/15 11:09
 *
 * @author zhangyingying
 * @since JDK 1.8
 */
public interface BookService {

    public int addBook(Book book);

    public int deleteBook(int id);

    public int updateBook(Book book);

    public Book queryBookById(int id);

    public List<Book> queryBook();
}

BookServiceImpl接口实现类

package com.yitong.service.impl;

import com.yitong.bean.Book;
import com.yitong.dao.BookDao;
import com.yitong.dao.impl.BookDaoImpl;
import com.yitong.service.BookService;

import java.util.List;

/**
 * ClassName: BookServiceImpl
 * Description:
 * date: 2021/12/15 11:09
 *
 * @author zhangyingying
 * @since JDK 1.8
 */
public class BookServiceImpl implements BookService {
    private BookDao bookDao = new BookDaoImpl();

    @Override
    public int addBook(Book book) {
        bookDao.addBook(book);
        return bookDao.addBook(book);
    }

    @Override
    public int deleteBook(int id) {
        return bookDao.deleteBookById(id);
    }

    @Override
    public int updateBook(Book book) {
        return bookDao.updateBook(book);
    }

    @Override
    public Book queryBookById(int id) {
        return bookDao.queryBookById(id);
    }

    @Override
    public List<Book> queryBook() {
        return bookDao.queryBooks();
    }
}

BookServiceTest测试类

package com.yitong.test;

import com.yitong.bean.Book;
import com.yitong.service.BookService;
import com.yitong.service.impl.BookServiceImpl;
import org.junit.Test;

import java.math.BigDecimal;
import java.util.List;

import static org.junit.Assert.*;

/**
 * ClassName: BookServiceTest
 * Description:
 * date: 2021/12/15 11:23
 *
 * @author zhangyingying
 * @since JDK 1.8
 */
public class BookServiceTest {
    private BookService bookService = new BookServiceImpl();
    @Test
    public void addBook() {
        bookService.addBook(new Book(null,"国哥在手,天下我有!", "1125", new BigDecimal(1000000),
                100000000,0,null));
    }

    @Test
    public void deleteBook() {
        bookService.deleteBook(21);
    }

    @Test
    public void updateBook() {
        bookService.updateBook(new Book(42,"国哥在手,天下我有!", "1125", new BigDecimal(1000000),
                100000000,0,null));
    }

    @Test
    public void queryBookById() {
        System.out.println(bookService.queryBookById(30));

    }

    @Test
    public void queryBook() {
        List<Book> books = bookService.queryBook();
        for (Book book : books) {
            System.out.println(book);
        }
    }
}

2.5、编写图书模块的WEB层和页面联调测试

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ivzrugaW-1647832234572)(file:///C:/Users/ZHANGY~1/AppData/Local/Temp/企业微信截图_16396228971970.png)]

BaseServlet

package com.yitong.controller;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.lang.reflect.Method;

public abstract class BaseServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //URL只能使用get方法提交,我们用doGet方法调用doPost方法
        doPost(req,resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //从表单中获取action的值,从而调用相应的方法
        String action = req.getParameter("action");
        try {
            //通过action业务鉴别字符串,获取相应的业务,方法反射对象
            Method declaredMethod = this.getClass().getDeclaredMethod(action,HttpServletRequest.class,HttpServletResponse.class);
            //调用目标业务方法
            declaredMethod.invoke(this,req,resp);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

BookServlet

package com.yitong.controller;

import com.yitong.bean.Book;
import com.yitong.service.BookService;
import com.yitong.service.impl.BookServiceImpl;
import com.yitong.utils.WebUtils;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;

public class BookServlet extends BaseServlet{

    private BookService bookService = new BookServiceImpl();

    //查询所有书籍并显
    protected void list(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //通过BookService查询全部图书
        List<Book> books = bookService.queryBook();
        //把全部图书保存到Request域中
        req.setAttribute("books",books);
        //请求转发到/pages/manager/book_manager.jsp页面
        req.getRequestDispatcher("/pages/manager/book_manager.jsp").forward(req,resp);
    }

book_manager.jsp

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>图书管理</title>
	<%--静态包含base标签,css样式,jQuery文件--%>
	<%@include file="/pages/common/head.jsp"%>
</head>
<body>
	
	<div id="header">
			<img class="logo_img" alt="" src="../../static/img/logo.gif" >
			<span class="wel_word">图书管理系统</span>
		<%--静态包含manager管理模块的菜单--%>
		<%@include file="/pages/common/manager_menu.jsp"%>
	</div>
	
	<div id="main">
		<table>
			<tr>
				<td>名称</td>
				<td>价格</td>
				<td>作者</td>
				<td>销量</td>
				<td>库存</td>
				<td colspan="2">操作</td>
			</tr>
            
			<c:forEach items="${requestScope.books}" var="book">
				<tr>
					<td>${book.name}</td>
					<td>${book.price}</td>
					<td>${book.author}</td>
					<td>${book.sales}</td>
					<td>${book.stock}</td>
					<td><a href="book_edit.jsp">修改</a></td>
					<td><a href="#">删除</a></td>
				</tr>
			</c:forEach>

			<tr>
				<td></td>
				<td></td>
				<td></td>
				<td></td>
				<td></td>
				<td></td>
				<td><a href="book_edit.jsp">添加图书</a></td>
			</tr>	
		</table>
	</div>

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

修改【图书管理】请求地址

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<div>
    //修改请求地址
    <a href="manager/bookServlet?action=list">图书管理</a>
    <a href="pages/manager/order_manager.jsp">订单管理</a>
    <a href="index.jsp">返回商城</a>
</div>

前后台请求地址区别

项目一般分为前后台

前台:是给普通用户使用,一般不需要权限检查就可以访问资源,或者功能都属于前台功能。比如淘宝不登陆就可以访问的首页(包含商品浏览)前台地址为:client/bookServlet/

后台:是写给管理员使用的。一般都需要权限检查才能访问到的资源,或页面或功能,是后台。后台的地址为:manager/bookServlet/

2.6、添加图书

? 表单重复提交:当用户提交完请求,浏览器会记录下最后一次请求的全部信息,当用户按F5刷新的时候,数据就会再次提交,浏览器再次发送请求给后台就会再次执行添加操作。

? 点击添加图书按钮,跳转到添加页面,填写完对应信息之后点击提交,执行add方法将数据添加到数据库中。然后通过重定向跳回书籍列表页面。

添加书籍信息页面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>编辑图书</title>
	<%--静态包含base标签,css样式,jQuery文件--%>
	<%@include file="/pages/common/head.jsp"%>
<style type="text/css">
	h1 {
		text-align: center;
		margin-top: 200px;
	}
	
	h1 a {
		color:red;
	}
	
	input {
		text-align: center;
	}
</style>
</head>
<body>
		<div id="header">
			<img class="logo_img" alt="" src="../../static/img/logo.gif" >
			<span class="wel_word">编辑图书</span>
			
			<%--静态包含manager管理模块的菜单--%>
			<%@include file="/pages/common/manager_menu.jsp"%>
		</div>
		
		<div id="main">
			<form action="manager/bookServlet" method="get">
				<input type="hidden" name="action" value="add">
				<table>
					<tr>
						<td>名称</td>
						<td>价格</td>
						<td>作者</td>
						<td>销量</td>
						<td>库存</td>
						<td colspan="2">操作</td>
					</tr>		
					<tr>
						<td><input name="name" type="text" value="时间简史"/></td>
						<td><input name="price" type="text" value="30.00"/></td>
						<td><input name="author" type="text" value="霍金"/></td>
						<td><input name="sales" type="text" value="200"/></td>
						<td><input name="stock" type="text" value="300"/></td>
						<td><input type="submit" value="提交"/></td>
					</tr>	
				</table>
			</form>
		</div>
		<%--静态包含页脚内容--%>
		<%@include file="/pages/common/footer.jsp"%>
</body>
</html>

添加图书Servlet

protected void add(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    Book book = WebUtils.copyParamToBean(req.getParameterMap(), new Book());
    bookService.addBook(book);
    
    /* 请求转发的 / 表示工程名,重定向的 / 表示端口号 */
    //重定向
    resp.sendRedirect(req.getContextPath() + "/manager/bookServlet?action=list");
}

2.7、删除图书信息

删除jsp

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>图书管理</title>
	<%--静态包含base标签,css样式,jQuery文件--%>
	<%@include file="/pages/common/head.jsp"%>
	<script type="text/javascript">
		$(function (){
			$("a.deleteclass").click(function (){
				//在时间的function函数中,有一个this对象,这个this对象,是当前正在相应事件的dom对象。
				/*
				* confirm是是确认提示框函数
				* 参数是它的提示内容
				* 它有两个按钮,一个确认,一个是取消
				* 返回true表示点击了确认按钮,返回false表示点击取消
				*/
				return confirm("你确定要删除" + $(this).parent().parent().find("td:first").text() + "吗?");
			});
		});
	</script>
</head>
<body>
	<div id="header">
			<img class="logo_img" alt="" src="../../static/img/logo.gif" >
			<span class="wel_word">图书管理系统</span>
		<%--静态包含manager管理模块的菜单--%>
		<%@include file="/pages/common/manager_menu.jsp"%>
	</div>
	
	<div id="main">
		<table>
			<c:forEach items="${requestScope.books}" var="book">
				<tr>
					<td>${book.name}</td>
					<td>${book.price}</td>
					<td>${book.author}</td>
					<td>${book.sales}</td>
					<td>${book.stock}</td>
					<td><a href="book_edit.jsp">修改</a></td>
					<td><a class="deleteclass" href="manager/bookServlet?action=delete&id=${book.id}">删除</a></td>
				</tr>
			</c:forEach>	
		</table>
	</div>

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

删除Servlet

protected void delete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    String id = req.getParameter("id");
    int i = WebUtils.parseInt(id, 0);
    /*        int i = 0;
        try {
            i = Integer.parseInt(id);
        }catch (Exception e){
            e.printStackTrace();
        }*/
    bookService.deleteBook(i);
    //删除后重定向到展示所有信息的页面
    resp.sendRedirect(req.getContextPath() + "/manager/bookServlet?action=list");
}

2.8、修改图书信息

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nGr9Vx0p-1647832234580)(file:///C:/Users/ZHANGY~1/AppData/Local/Temp/企业微信截图_16399641294841.png)]

? jsp页面不能直接携带数据到下一个页面,因此在图书列表管理页面不能直接到图书信息修改页面,它要去数据库中获取当前修改的图书对应信息。所以要经过servlet将数据从数据库中获取出来。展示到页面

2.8.1、将要修改的图书信息展示到修改页面

修改列表页面信息

<%--
    a标签中的跳转请求中斜杠的用法
    开头加斜杠表示在端口号后面加请求地址
    开头不加斜杠表示在工程名后加请求地址
    将修改请求的连接改为将要修改的信息展示
--%>
<td><a href="manager/bookServlet?action=getBook&id=${book.id}">修改</a></td>
<td><a class="deleteclass" href="manager/bookServlet?action=delete&id=${book.id}">删除</a></td>
</tr>
</c:forEach>

BookServlet程序中添加getBook方法

protected void getBook(HttpServletRequest req,HttpServletResponse resp) throws ServletException,IOException{
    //1 获取请求的参数图书编号
    int id = WebUtils.parseInt(req.getParameter("id"),0);
    //2 调用bookService.queryBookById查询图书
    Book book = bookService.queryBookById(id);
    //3 保存到图书到Request域中
    req.setAttribute("book",book);
    //4 请求转发到pages/manager/book_edit.jsp页面
    req.getRequestDispatcher("/pages/manager/book_edit.jsp").forward(req.resp);
}

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

<div id="main">
    <form action="manager/bookServlet" method="get">
        <input type="hidden" name="action" value="add"/>
        <table>
            <tr>
                <td>名称</td>
                <td>价格</td>
                <td>作者</td>
                <td>销量</td>
                <td>库存</td>
                <td colspan="2">操作</td>
            </tr>
            <tr>
                <td><input name="name" type="text" value="${requestScope.book.name}"/></td>
                <td><input name="price" type="text" value="${requestScope.book.price}"/></td>
                <td><input name="author" type="text" value="${requestScope.book.author}"/></td>
                <td><input name="sales" type="text" value="${requestScope.book.sales}"/></td>
                <td><input name="stock" type="text" value="${requestScope.book.stock}"/></td>
                <td><input type="submit" value="提交"</td>
            </tr>
        </table>
    </form>
</div>

2.8.2、将修改后的数据存储到数据库并跳回图书列表页面

遇到的问题是:book_edit.jsp页面,既要做添加此操作又要做修改操作。。而到底是添加还是修改是由一个隐藏域来决定的。如何动态修改隐藏域让它的值即可实现添加。又可以实现修改操作

解决方案一:可以在请求发起时,附带上当前要操作的值。并注入到隐藏域中。

book_manager.jsp

<div id="main">
    <table>
        <tr>
            <td>名称</td>
            <td>价格</td>
            <td>作者</td>
            <td>销量</td>
            <td>库存</td>
            <td colspan="2">操作</td>
        </tr>
        <c:forEach items="${requestScope.books}" var="book">
            <tr>
                <td>${book.name}</td>
                <td>${book.price}</td>
                <td>${book.author}</td>
                <td>${book.sales}</td>
                <td>${book.stock}</td>
                <%--
    				a标签中的跳转请求中斜杠的用法
    				开头加斜杠表示在端口号后面加请求地址
    				开头不加斜杠表示在工程名后加请求地址
    			--%>
                <td><a href="manager/bookServlet?action=getBook&id=${book.id}&method=update">修改</a></td>
                <td><a class="deleteclass" href="manager/bookServlet?action=delete&id=${book.id}">删除</a></td>
            </tr>
        </c:forEach>

        <tr>
            <td></td>
            <td></td>
            <td></td>
            <td></td>
            <td></td>
            <td></td>
            <td><a href="pages/manager/book_edit.jsp?method=add">添加图书</a></td>
        </tr>	
    </table>
</div>

book_edit.jsp

<div id="main">
    <form action="manager/bookServlet" method="get">
        <%--可以通过请求的method属性来判断这个页面用来复用那个功能--%>
        <input type="hidden" name="action" value="${param.method}">
        <table>
            <tr>
                <td>名称</td>
                <td>价格</td>
                <td>作者</td>
                <td>销量</td>
                <td>库存</td>
                <td colspan="2">操作</td>
            </tr>		
            <tr>
                <td><input name="name" type="text" value="${requestScope.book.name}"/></td>
                <td><input name="price" type="text" value="${requestScope.book.price}"/></td>
                <td><input name="author" type="text" value="${requestScope.book.author}"/></td>
                <td><input name="sales" type="text" value="${requestScope.book.sales}"/></td>
                <td><input name="stock" type="text" value="${requestScope.book.stock}"/></td>
                <td><input type="submit" value="提交"/></td>
            </tr>	
        </table>
    </form>
</div>

解决方案二:可以通过判断当前请求参数中是否包含有id参数,如果有说明是修改操作,如果没有说明是添加操作。

<div id="main">
    <form action="manager/bookServlet" method="get">
        <%--
    		判断请求数据的id是否为空,如果为空就为添加信息,不为空就是修改信息
    	--%>
        <input type="hidden" name="action" value="${empty param.id ? "add" : "update"}">
        <table>
            <tr>
                <td>名称</td>
                <td>价格</td>
                <td>作者</td>
                <td>销量</td>
                <td>库存</td>
                <td colspan="2">操作</td>
            </tr>		
            <tr>
                <td><input name="name" type="text" value="${requestScope.book.name}"/></td>
                <td><input name="price" type="text" value="${requestScope.book.price}"/></td>
                <td><input name="author" type="text" value="${requestScope.book.author}"/></td>
                <td><input name="sales" type="text" value="${requestScope.book.sales}"/></td>
                <td><input name="stock" type="text" value="${requestScope.book.stock}"/></td>
                <td><input type="submit" value="提交"/></td>
            </tr>	
        </table>
    </form>
</div>

解决方案三:可以通过判断,Request域中是否包含有修改的图书信息对象,如果没有说明是添加操作,如果有说明是修改操作。

<div id="main">
    <form action="manager/bookServlet" method="get">
        <%--
    		判断request是否为空,如果为空就为添加信息,不为空就是修改信息
    	--%>
        <input type="hidden" name="action" value="${empty requestScope.book ? "add" : "update"}">
        <table>
            <tr>
                <td>名称</td>
                <td>价格</td>
                <td>作者</td>
                <td>销量</td>
                <td>库存</td>
                <td colspan="2">操作</td>
            </tr>		
            <tr>
                <td><input name="name" type="text" value="${requestScope.book.name}"/></td>
                <td><input name="price" type="text" value="${requestScope.book.price}"/></td>
                <td><input name="author" type="text" value="${requestScope.book.author}"/></td>
                <td><input name="sales" type="text" value="${requestScope.book.sales}"/></td>
                <td><input name="stock" type="text" value="${requestScope.book.stock}"/></td>
                <td><input type="submit" value="提交"/></td>
            </tr>	
        </table>
    </form>
</div>

在BookServlet程序中添加update方法

//更新书籍信息
protected void update(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    //获取请求数据
    Map parameterMap = req.getParameterMap();
    //注入到javaBean中
    Book book = WebUtils.copyParamToBean(parameterMap, new Book());
    //调用bookService.updateBook(book)
    bookService.updateBook(book);
    //重定向到书籍列表
    resp.sendRedirect(req.getContextPath() + "/manager/bookServlet?action=list");
}

在修改图书信息的时候需要id,因此我们在请求update时需要把id传回去,我们把id属性写在隐藏域中,这个时候就可以更新了。

<input type="hidden" name="id" value="${requestScope.book.id}">

3、图书分页分析

3.1、分页模块的分析

由分页的视图分析出分页的对象模型Page模型

pageNo 当前页码

pageTotal 总页码

pageTotalCount 总记录数

pageSize 每页显示数量

items 当前页数据

这些属性的值都怎么确定?

  • pageNo:当前页码是由客户端进行传递

  • pageSize:每页显示数量由两种因素决定

    • 客户端进行传递
    • 由页面布局决定
  • pageTotalCount:总记录数可以由sql语句求得。

    sql语句是:select count(*) from 表名

  • pageTotal:总页码可以由总记录数/每页数量得到。

    注:总记录数%每页的数量>0,则总页码+1

  • item是当前页数据,也可以由sql语句求得。

    sql语句的范围都是前闭后开区间,可以理解为1-4就是0-3,类比数组下标。不包含最后一个。

    sql:select * from 表名 limit begin , pageSize;

    begin可以由公式求得:(pageNo-1)x pageSize;

    假设,当前是第1页,每页5条记录,则begin = (1-1)x 5 得0;

    假设,当前是第2页,每页5条记录,则begin = (2-1)x 5 得5;

    假设,当前是第3页,每页5条记录,则begin = (3-1)x 5 得10;

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wj7mzJRv-1647832234580)(C:\Users\zhangyingying\AppData\Roaming\Typora\typora-user-images\image-20211220145754282.png)]

  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2022-03-22 20:27:56  更:2022-03-22 20:31:49 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 5:07:21-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码