JavaWeb学习笔记(5)-B站尚硅谷

文章目录

十四、书城项目第三阶段——优化

(1)页面jsp动态化

如果想让页面动态化,要将html页面变为jsp
1、首先在所有html页面的顶部加上 page指令
	<%@ page contentType="text/html;charset=UTF-8" language="java" %>
2、然后修改文件后缀名 从 .html 变为 .jsp
3、页面内有些代码也要从 .html 变为 .jsp
	使用快捷键: ctrl+shift+r 查找替换
	如下图
		搜索 .html 
		替换为 .jsp
		在Directory中搜索,Directory目录选pages
		Replace All 全部替换

在这里插入图片描述

(2)抽取页面中相同的内容

A.登录成功的菜单

在这里插入图片描述

在如上jsp页面中都有 如下的 登录成功的菜单代码:

在这里插入图片描述

在pages目录下,创建一个common目录

在common目录下创建 login_success_menu.jsp 
	然后将上面的登录成功的菜单代码写进该jsp

login_success_menu.jsp 如下:

在这里插入图片描述

然后再将其他页面中的登录成功的菜单代码删除,用下面的静态包含代码替换:
	<!--静态包含,登录成功之后的菜单-->
	<%@ include file="/pages/common/login_success_menu.jsp"%>

B.base、css、jQuery标签

将所有页面的base、css、jQuery标签提取

在common目录下创建 head.jsp
将以下代码写入:
	<base href="http://localhost:8080/09_bookproject/">
	<link type="text/css" rel="stylesheet" href="static/css/style.css" >
	<script type="text/javascript" src="static/jquery-3.6.0.js"></script>
	
	head.jsp如下:

在这里插入图片描述

将pages目录下(除common目录)的所有jsp页面和index.jsp页面的
	base、css、jQuery标签用下面的代替:
		不管是只有一个css 没有base和jQuery 等情况,都这样做
		<!--静态包含,base标签,css标签,jQuery文件-->
		<%@ include file="/pages/common/head.jsp"%>

因为所有页面都使用了base,所以要对每个程序中的代码都看看需不需要修改。

login_success_menu.jsp 需要修改为如下(因为所有页面都使用了base):
在这里插入图片描述

如果出现错误找不到文件:alt + enter 选set context folder to / for ...

C.每个页面的页脚

页脚都是相同的,在common目录下创建footer.jsp 写入如下代码:

在这里插入图片描述

使用如下代码替换:
	<%@ include file="/pages/common/footer.jsp" %>

D.manager模块的菜单

manager模块的菜单代码是重复的,多个页面都有
在common目录下创建manager_menu.jsp,写入以下代码:

在这里插入图片描述

使用以下代码代替原来的代码:
		<%@ include file="/pages/common/manager_menu.jsp"%>

(3)登录、注册错误提示和表单回显

登录或注册失败,需要提示用户错误信息。
登录或注册失败之后,表单中的有些内容是不会被清空的,会保留下来。

在这里插入图片描述

针对登录,实现错误信息提示和登陆错误之后保留用户名不被清空:
修改LoginServlet:

在这里插入图片描述

然后修改 login.jsp:
提示错误信息:

在这里插入图片描述

登录错误之后,保存用户名不被清空,即填写value值:

在这里插入图片描述


针对注册,实现错误信息提示(用户名已存在和验证码错误)和注册失败之后 用户名和邮箱不被清空

修改RegisterServlet:

在这里插入图片描述
在这里插入图片描述

修改regist.jsp:
输出错误提示信息:

在这里插入图片描述

注册错误后,保留用户名不被清空,即value:

在这里插入图片描述

注册错误后,保留邮箱不被清空,即value:

在这里插入图片描述

错误提示信息是写在标签上的,一般使用div或span;
但是错误信息的触发是写在servlet程序中的,通过判断错误,将错误信息保存在request域中,这样jsp页面也就能使用错误信息。

(4)BaseServlet的抽取

A. 代码优化:合并 LoginServlet 和 RegistServlet 程序为 UserServlet

一般在一个模块中,只有一个Servlet程序;
现在只有一个用户模块,但是有两个Servlet程序:LoginServlet和RegisterServlet
现在要把这两个合并为一个Servlet程序叫UserServlet
但是 那两个Servlet程序都是使用的doPost()方法,该怎么合并呢?

在登录和注册表单使用hidden标签,hidden标签在页面中不显示出来,
但是可以给hidden的value设置不同的值来判断是登录还是注册。

在这里插入图片描述

创建UserServlet:写web.xml,把LoginServlet和RegisterServlet复制过去
	不过为了代码简洁,在UserServlet中创建两个方法:login和register
		将LoginServlet复制到login方法中
		将RegisterServlet复制到register方法中
package com.atguigu.web;

import com.atguigu.bean.User;
import com.atguigu.service.UserService;
import com.atguigu.service.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 {
    
    

    //web层只能操作service层,不能直接操作dao层
    private UserService userService = new UserServiceImpl();

    //处理登录的需求
    protected void login(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    

        // 1、获取请求的参数
        String username = req.getParameter("username");
        String password = req.getParameter("password");

        // 调用 userService.login()登录处理业务
        //判断数据库中是否有该用户
        User loginUser = userService.login(new User(null, username, password, null));

        // 如果等于 null,说明没有该用户,说明登录 失败!
        if (loginUser == null) {
    
    

            //把错误信息 和 回显的表单项信息(这里只回显用户名)保存在request域中
            req.setAttribute("msg", "用户名或密码错误!");
            req.setAttribute("username", username);

            // 跳回登录页面
            req.getRequestDispatcher("/pages/user/login.jsp").forward(req, resp);
        } else {
    
    
            // 登录 成功
            //跳到成功页面 login_success.jsp
            req.getRequestDispatcher("/pages/user/login_success.jsp").forward(req, resp);
        }
    }


    //处理注册的需求
    protected void register(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)
        //equalsIgnoreCase()忽略大小写
        if("abcde".equalsIgnoreCase(code)){
    
    
            //2.1.验证码正确
            //3.检查用户名是否可用
            if(userService.existUsername(username)){
    
    
                //3.1.用户名已存在,跳转回注册界面
                System.out.println("用户名[" + username + "]已存在!");


                //把回显信息保存在request域中
                //错误提示信息:
                req.setAttribute("msg", "用户名已存在!");
                //保留用户名和邮箱信息,在注册失败后不被清空
                req.setAttribute("username", username);
                req.setAttribute("email", email);


                req.getRequestDispatcher("/pages/user/regist.jsp").forward(req, resp);
            }else{
    
    
                //3.2.用户名可用,将注册的用户保存到数据库,注册成功
                userService.registerUser(new User(null,username,password,email));
                //跳转到注册成功页面
                req.getRequestDispatcher("/pages/user/regist_success.jsp").forward(req, resp);
            }
        }else{
    
    
            //2.2.验证码错误,跳转回注册页面
            System.out.println("验证码[" + code +"]错误");


            //把回显信息保存在request域中
            //错误提示信息:
            req.setAttribute("msg", "验证码错误!");
            //保留用户名和邮箱信息,在注册失败后不被清空
            req.setAttribute("username", username);
            req.setAttribute("email", email);


            req.getRequestDispatcher("/pages/user/regist.jsp").forward(req, resp);
        }
    }


    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    

        String action = req.getParameter("action");

        if ("login".equals(action)){
    
    
            //处理登录的需求
            login(req, resp);

        }else if ("register".equals(action)){
    
    
            //处理注册的需求
            register(req, resp);

        }

    }
}

在这里插入图片描述

为登录表单添加hidden标签,同时修改form 的action:
action直接写 userServlet也行

在这里插入图片描述

为注册表单添加hidden标签,同时修改form 的action:

在这里插入图片描述

LoginServelt和RegisterServelt可以删除了,相应的web.xml中的配置也可以删除。

B. 优化代码二:使用反射优化大量 else if

在这里插入图片描述

如果还用其他的功能,那么在UserServlet的doPost()方法中就要写更多的else if
如何优化,不写那么多的else if?
使用 反射的 方法,只要知道要调用的方法名,就可以调用相应的方法。
修改UserServlet的doPost()方法如下:

在这里插入图片描述

C. 代码优化三:抽取 BaseServlet 程序

在这里插入图片描述
在这里插入图片描述

现在只有用户模块UserServlet程序,但是以后可能会有更多的模块比如图书模块BookServlet程序。
这些模块都会有一些共同的代码,即doPost()里是一样的,
	所以再将doPost()提取出来放进BaseServlet程序中,UserServlet和BookServlet中不再写doPost()
	BaseServlet是父类,所以定义为抽象的abstract,并继承HttpServlet
	UserServlet和BookServlet只继承BaseServlet即可。

	程序运行时会先进入BaseServlet,然后再进入相应的UserServlet或BookServlet。
	
	如果理解不了,可以这样想,UserServlet继承了BaseServlet,就只是把doPost()方法换了一个地方,你可以想成doPost()还在UserServlet中。
	
	表单提交访问的是UserServlet,提交方式是post,所以会看UserServlet中有无doPost()方法,其实是有的,不过写在了BaseServlet里,然后继承了。
	
	web.xml不需要修改。
package com.atguigu.web;

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

public class BaseServlet extends HttpServlet {
    
    
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    
    

        //功能的方法名要和表单中的hidden标签的value值一致
        //比如:登录表单的hidden标签的value=login,上面的方法名也是login
        //获取hidden的value值
        String action = req.getParameter("action");

        try {
    
    
            //通过反射机制,调用不同的功能方法(多一个功能,就在上面多写一个方法,doPost里面就不用改了)
            //getDeclaredMethod(指明要获取的方法名,指明获取的方法的形参列表)
            Method method = this.getClass().getDeclaredMethod(action, HttpServletRequest.class, HttpServletResponse.class);

            //调用相应的功能方法
            method.invoke(this,req,resp);

        } catch (Exception e) {
    
    
            e.printStackTrace();
        }

    }
}

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

在UserServlet的登录和注册操作中,都会获取请求参数,并注入JavaBean(User类)中
就是下面这个:

    //1.获取请求的参数
    String username = req.getParameter("username");
    String password = req.getParameter("password");
    String email = req.getParameter("email");

	User user = new User(null,username,password,email)

	可以对获取请求参数进行封装,使用BeanUtils工具类

在这里插入图片描述

创建一个新的类:WebUtils:
package com.atguigu.web;

import org.apache.commons.beanutils.BeanUtils;

import java.lang.reflect.InvocationTargetException;
import java.util.Map;

public class WebUtils {
    
    

    //把Map中的值注入到对应的JavaBean属性中
    //value为请求参数,以Map键值对的形式出现(比如username=输入的 password=输入的 等)
    //bean是javabean对象,这里是User对象
    
    //使用泛型是因为 JavaBean是不一样的,可能是User类,也可能是Book类等等
    //使用泛型,就不用强制转换了。
    public static <T> T copyParamToBean(Map value, T bean){
    
    

        try {
    
    
            System.out.println("注入之前:" + bean);

            //将所有的请求参数都注入到user对象中
            //第一个参数是JavaBean对象,这里是user对象
            //第二个参数是 请求参数(以键值对的方式)
            BeanUtils.populate(bean, value);

            System.out.println("注入之后:" + bean);
        } catch (Exception e) {
    
    
            e.printStackTrace();
        }
		
		//将创建的对象返回
        return bean;
    }
}

如何调用WebUtils?
	
	User user = WebUtils.copyParamToBean(req.getParameterMap(), new User());

	使用BeanUtils可以不写获取请求参数,直接将请求参数注入到JavaBean中
	(即直接创建一个user对象)
	
	BeanUtils.populate(bean, value);的底层原理是:
		获取到传入的req.getParameterMap() 键值对 形式 的请求参数 之后,
		会调用JavaBean类 即User类中的setXXX方法,将键值对的值传进去,从而创建出一个User对象。

	但是登录或注册的方法中 下面有的代码还是要用到 请求参数,
	所以还是要手动写请求参数,这个WebUtils没啥用啊,我就没写WebUtils,还跟原来一样。

十五、书城项目第四阶段——使用EL表达式修改表单回显

EL的作用是替换 <%= %>
一般都是使用EL 来替换 表达式脚本 <%= %>

使用EL表达式对login.jsp做如下修改:

在这里插入图片描述
在这里插入图片描述

使用EL表达式对regist.jsp做如下修改:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

十六、书城项目第五阶段——编写图书模块

001-MVC概念

在这里插入图片描述
在这里插入图片描述

002-编写图书模块的数据库表

创建图书表:
	id 需要一个id号
	name 图书名
	price 图书价格 decimal(11,2)--->decimal十进制数,2表示小数的位数,“11”指的是整数部分加小数部分的总长度
	author 图书作者
	sales 销量
	stock 库存量
	img_path 图书照片的路径
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;

003-编写图书模块的JavaBean

在这里插入图片描述

package com.atguigu.bean;

import java.math.BigDecimal;

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;
        
        //当imgPath为空时,不让它赋值,让它使用默认值;当imgPath不为空时,赋新值。
        if (imgPath != null && !imgPath.equals("")){
    
    
            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) {
    
    
        //当imgPath为空时,不让它赋值,让它使用默认值;当imgPath不为空时,赋新值。
        if (imgPath != null && !imgPath.equals("")){
    
    
            this.imgPath = imgPath;
        }
    }

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

004-编写图书模块的Dao和测试Dao

BookDao 接口:
package com.atguigu.dao;

import com.atguigu.bean.Book;

import java.util.List;

public interface BookDao {
    
    

    //增加书
    public int addBook(Book book);

    //通过id删除书
    public int deleteBookById(Integer id);

    //修改书的信息
    public int updateBook(Book book);

    //通过id查询书
    public Book queryBookById(Integer id);

    //查询所有的书
    public List<Book> queryBooks();
}

BookDaoImpl 实现类(继承BaseDao,实现BookDao):
package com.atguigu.dao.dao_impl;

import com.atguigu.bean.Book;
import com.atguigu.dao.BaseDao;
import com.atguigu.dao.BookDao;

import java.util.List;

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(?,?,?,?,?,?)";

        return update(sql,book.getName(),book.getAuthor(),book.getPrice(),book.getSales(),book.getStock(),book.getImgPath());

    }

    @Override
    //通过id删除书
    public int deleteBookById(Integer id) {
    
    

        String sql = "delete from t_book where id = ?";

        return update(sql, id);
    }

    @Override
    //修改书的信息
    public int updateBook(Book book) {
    
    

        String sql = "update t_book set `name`=?,`author`=?,`price`=?,`sales`=?,`stock`=?,`img_path`=? where id = ?";

        return update(sql,book.getName(),book.getAuthor(),book.getPrice(),book.getSales(),book.getStock(),book.getImgPath(),book.getId());
    }

    @Override
    //通过id查询书
    public Book queryBookById(Integer id) {
    
    

        String sql = "select `id` , `name` , `author` , `price` , `sales` , `stock` , `img_path` imgPath from t_book where id = ?";

        return queryForOne(Book.class, sql,id);
    }

    @Override
    //查询所有的书
    public List<Book> queryBooks() {
    
    

        String sql = "select `id` , `name` , `author` , `price` , `sales` , `stock` , `img_path` imgPath from t_book";

        return queryForList(Book.class, sql);
    }
}

package com.atguigu.test;

import com.atguigu.bean.Book;
import com.atguigu.dao.BookDao;
import com.atguigu.dao.dao_impl.BookDaoImpl;
import org.junit.jupiter.api.Test;

import java.math.BigDecimal;

class BookDaoImplTest {
    
    

    private BookDao bookDao = new BookDaoImpl();

    @Test
    void addBook() {
    
    
        bookDao.addBook(new Book(null,"国哥为什么这么帅!", "191125", new BigDecimal(9999),1100000,0,null));
    }

    @Test
    void deleteBookById() {
    
    
        bookDao.deleteBookById(21);
    }

    @Test
    void updateBook() {
    
    
        bookDao.updateBook(new Book(21,"大家都可以这么帅!", "国哥", new BigDecimal(9999),1100000,0,null));
    }

    @Test
    void queryBookById() {
    
    
        System.out.println( bookDao.queryBookById(21) );
    }

    @Test
    void queryBooks() {
    
    
        for (Book queryBook : bookDao.queryBooks()) {
    
    
            System.out.println(queryBook);
        }
    }
}

005-编写图书模块的Service和测试Service

BookService接口:
package com.atguigu.service;

import com.atguigu.bean.Book;

import java.util.List;

public interface BookService {
    
    
    //增加书
    public void addBook(Book book);

    //通过id删除书
    public void deleteBookById(Integer id);

    //修改书的信息
    public void updateBook(Book book);

    //通过id查询书
    public Book queryBookById(Integer id);

    //查询所有的书
    public List<Book> queryBooks();
}

BookServiceImpl实现类:
package com.atguigu.service.service_impl;

import com.atguigu.bean.Book;
import com.atguigu.dao.BookDao;
import com.atguigu.dao.dao_impl.BookDaoImpl;
import com.atguigu.service.BookService;

import java.util.List;

public class BookServiceImpl implements BookService {
    
    

    private BookDao bookDao = new BookDaoImpl();

    @Override
    //增加书
    public void addBook(Book book) {
    
    
        bookDao.addBook(book);
    }

    @Override
    //通过id删除书
    public void deleteBookById(Integer id) {
    
    
        bookDao.deleteBookById(id);
    }

    @Override
    //修改书的信息
    public void updateBook(Book book) {
    
    
        bookDao.updateBook(book);
    }

    @Override
    //通过id查询书
    public Book queryBookById(Integer id) {
    
    
        return bookDao.queryBookById(id);
    }

    @Override
    //查询所有的书
    public List<Book> queryBooks() {
    
    
        return bookDao.queryBooks();
    }
}

package com.atguigu.test;

import com.atguigu.bean.Book;
import com.atguigu.service.BookService;
import com.atguigu.service.service_impl.BookServiceImpl;
import org.junit.jupiter.api.Test;

import java.math.BigDecimal;


class BookServiceImplTest {
    
    

    private BookService bookService = new BookServiceImpl();

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

    }

    @Test
    void deleteBookById() {
    
    
        bookService.deleteBookById(22);
    }

    @Test
    void updateBook() {
    
    
        bookService.updateBook(new Book(22,"社会我国哥,人狠话不多!", "1125", new BigDecimal(999999),
                10, 111110, null));
    }

    @Test
    void queryBookById() {
    
    
        System.out.println(bookService.queryBookById(22));
    }

    @Test
    void queryBooks() {
    
    
        for (Book queryBook : bookService.queryBooks()) {
    
    
            System.out.println(queryBook);
        }
    }
}

006-编写图书模块的Web层和页面联调测试

(1)实现获取图书信息功能

创建一个BookServlet类继承BaseServlet
BookServlet类中每一个方法都代表一个功能,那么图书模块需要哪些功能?
	添加图书
	删除图书
	修改图书
	图书列表的查询

在这里插入图片描述
在这里插入图片描述

这里的url-pattern有点不一样,是:/manager/bookServlet (BookServlet的访问地址)
为了后面的权限管理做准备,不是因为有manager目录。

为什么要写为:/manager/bookServlet ?

这里就涉及到了前后台的简单解释:
	添加/manager/是为了区分前后台,便于权限检查。

在这里插入图片描述


只有先查到了图书列表中的图书,才进行增删改操作,所以先实现 图书列表的查询

图解列表功能流程:

在这里插入图片描述

在首页点 后台管理--->点 图书管理 ---> 就可以看到所有图书的信息
图书管理页面就是pages/manager/book_manager.jsp页面(上面图片里写错了),
	也是所有图书信息页面。

但是想要在book_manager.jsp页面看到所有图书的信息,首先要从数据库获取所有图书的信息,
	book_manager.jsp页面本身是没有任何数据的
	所以要先通过BookServlet中的list方法获取所有的图书信息,将图书信息保存在request域中,
	再请求转发给book_manager.jsp页面

所以点击图书管理,先跳到 BookServlet程序
所以要修改 manager_menu.jsp 中图书管理的a标签的地址
如下:

在这里插入图片描述
注意:因为a标签使用的是get方法,所以需要在BaseServlet程序中再写一个doGet()方法,在doGet()方法中调用doPost()方法即可。否则会出现405错误。
在这里插入图片描述


实现BookServlet程序中的list()方法:

在这里插入图片描述


在book_manager.jsp中 实现需要实现的内容
(下面图片中不是manager.jsp写错了,应该是是book_manager.jsp):

在这里插入图片描述

首先导入JSTL需要的jar包:
JSTL的作用是代替 <% %>

在这里插入图片描述

修改book_manager.jsp中的代码:
使用JSTL遍历输出图书信息:
<%@ 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>

		<!--静态包含,后台管理系统的菜单-->
		<%@ 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="pages/manager/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="pages/manager/book_edit.jsp">添加图书</a></td>
			</tr>	
		</table>
	</div>

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

(2)实现添加图书功能

在这里插入图片描述

添加图书是在上面这个页面中,点击“添加图书”,跳转到book_edit页面。

在这里插入图片描述

修改book_edit.jsp:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


BookServlet中实现add方法:

在这里插入图片描述

点击提交后出现空白,将commons-beanutils-1.9.3 换为 commons-beanutils-1.8.0!

(3)实现删除图书的功能

在这里插入图片描述

在上面页面中点击删除,将删除请求发送给服务器,然后刷新页面发现这条数据消失。

在这里插入图片描述


修改book_manager.jsp:

将 删除 的 a标签的超链接地址改为:
	manager/bookServlet?action=delete&id=${book.id}
	点击删除,跳转到BookServlet,
	并且告诉BookServlet程序要调用的方法是delete 和 要删除的图书的id号

在这里插入图片描述


ctrl + alt + t —> surround with 快捷键 (包括try…catch…)

修改BookServlet程序,实现删除delete功能:

在这里插入图片描述

WebUtils中实现数字字符串转换为int类型:

在这里插入图片描述


实现功能:在点击删除之后,弹出弹窗确认是否删除。
	给表示删除的a标签,绑定单击事件。

修改book_manager.jsp代码:
	首先给表示删除的a标签添加一个class属性:

在这里插入图片描述
在这里插入图片描述

(4)实现修改图书功能

在这里插入图片描述
在这里插入图片描述

在上面这个页面(book_manager.jsp)点击修改跳转到book_edit.jsp页面
在book_edit.jsp页面显示要修改的那条数据信息
但是book_edit.jsp页面无法显示数据
所以点击 修改 先 跳转到 BookServlet 

在BookServlet创建方法 getBook() 获取到要修改的图书的信息
然后再将 这个信息 显示到 book_edit.jsp页面

然后 再 在book_edit.jsp页面 修改 要修改的图书信息
修改完之后,再提交给 BookServlet,通过update()方法 保存到 数据库中
然后 再 请求转发到 book_manager.jsp 显示所有图书列表

首先修改 book_manager.jsp 的 表示修改的 a标签 的地址:
	manager/bookServlet?action=getBook&id=${book.id}

	点击修改 跳转到 BookServlet
	并告诉 BookServlet 通过要修改的图书的id 调用 getBook()方法 ---> 获得要修改的图书的信息

在这里插入图片描述


修改 BookServlet :
创建 getBook() 方法 获得要修改的图书的信息
	将信息 保存在 request域 中
再 请求转发到 book_edit.jsp
这样 就可以在 book_edit.jsp 中 获取到 要修改的图书的信息

在这里插入图片描述


修改 book_edit.jsp : 将要修改的图书的信息 显示到页面上:

在这里插入图片描述


修改 BookServlet :
	实现update()方法 将修改的内容保存到数据库

注意:这里出现了一个问题:

在这里插入图片描述

解决方法一:

	在book_manager.jsp中,点击 添加图书 或 修改图书 的 a标签超链接时
	附带上 要操作 的 方法;并注入到隐藏域中

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
解决方法二:

可以判断当前请求参数中是否包含id参数,如果包含id说明是修改操作,如果不包含说明是添加操作。

因为修改的请求参数包括 id:
	<a href="manager/bookServlet?action=getBook&id=${book.id}">修改</a>
添加图书的请求参数不包括 id:
	<a href="pages/manager/book_edit.jsp">添加图书</a>

只需要对hidden标签的value值做如下修改:

在这里插入图片描述
解决方法三:

可以通过判断request域中是否包含 要修改的图书对象,如果没有说明是添加操作,如果有说明是修改操作。

因为点击 添加 会 直接跳到 book_edit.jsp 
而点击 修改,会先到BookServlet程序中调用getBook()方法获取要修改的图书对象

只需要对hidden标签的value值做如下修改:

在这里插入图片描述
三种解决办法选其中一个,我选第二个。

实现BookServlet中的update方法:

在这里插入图片描述

注意:这里出现了一个问题
	按照以上方法,bookService.updateBook(book) 方法中 book的id为null
	无法修改图书
	没有将要修改的图书的id 传过来
	所以在book_edit.jsp中再添加一个hidden标签:

在这里插入图片描述

十六、书城项目第五阶段——分页

JavaWeb学习笔记(6)-B站尚硅谷

十七、Cookie

001-什么是 Cookie?

1、Cookie 翻译过来是饼干的意思。
2、Cookie 是服务器通知客户端保存键值对的一种技术。
3、客户端有了 Cookie 后,每次请求都发送给服务器。
4、每个 Cookie的大小不能超过 4kb

002-如何创建 Cookie?

在这里插入图片描述
在这里插入图片描述

003-服务器如何获取 Cookie?

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

004-Cookie 值的修改

在这里插入图片描述
在这里插入图片描述

Cookie的值也不能是中文

005-浏览器查看 Cookie

在这里插入图片描述
在这里插入图片描述

006-Cookie 生命控制

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

007-Cookie 有效路径 Path 的设置

在这里插入图片描述
在这里插入图片描述

008-Cookie 练习—免输入用户名登录

在这里插入图片描述
在这里插入图片描述

十八、Session

001-什么是Session会话

在这里插入图片描述
Cookie在浏览器端,Session在服务器端

002-如何创建和获取Session

在这里插入图片描述
在这里插入图片描述

003-Session域数据的存储和获取

在这里插入图片描述

004-Session生命周期控制

在这里插入图片描述

如果session设置为永不超时,服务器这边就要越来越多的session,占用内存。

如何让当前session会话马上超时无效?
	不是像cookie 设置为0
	而是使用另一个API,即另一个方法:
		public void invalidate() 让当前 Session 会话马上超时无效

在这里插入图片描述

在这里插入图片描述


在这里插入图片描述


在这里插入图片描述
在这里插入图片描述


在这里插入图片描述

点一下,等3秒,session被销毁;
一秒点一下,timeout一直是3,session无法被销毁。

005-浏览器和 Session 之间是怎么关联的?

问题:在session的超时时长内,关闭浏览器,再打开浏览器,怎么session就没了?
	因为一关浏览器 cookie 就没了,那么sesison也就没了,要创建一个新的session

Session 技术,底层其实是基于 Cookie 技术来实现的。

在这里插入图片描述

十九、书城项目第六阶段

JavaWeb学习笔记(7)-B站尚硅谷

二十、书城项目第七阶段

JavaWeb学习笔记(8)-B站尚硅谷

二十一、Filter 过滤器

001-什么是Filter 过滤器?

在这里插入图片描述

002-基本使用示例

以Filter的作用:权限检查为例

在这里插入图片描述

在web目录下创建一个admin目录:有三个文件:a.html,a.jsp,和一张照片。
再在web目录下创建一个登陆页面:login.jsp
如果添加访问权限:访问a.jsp,可以在a.jsp中写以下代码,没有登陆,无法访问,跳转到login.jsp登录页面
但是如果访问html和照片,写不了如下代码,这时就要用到Filter。

在这里插入图片描述


在这里插入图片描述

注意:Filter类是javax.servlet.Filter
所以不能使用tomcat10 只能使用tomcat8
因为Tomcat10 用jakarta代替了javax
要给当前模块添加tomcat8的lib的jar包

在这里插入图片描述

package com.atguigu.filter;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.io.IOException;

public class AdminFilter implements Filter {
    
    

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    
    

    }

    @Override
    //专门用于拦截请求,过滤响应。
    //这里以拦截请求中的权限检查为例子
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
    
    
        HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
        HttpSession session = httpServletRequest.getSession();

        Object user = session.getAttribute("user");

        //如果等于null,说明没有登录,无法访问目标资源
        if (user == null){
    
    
            //转到login.jsp登录页面
            servletRequest.getRequestDispatcher("/login.jsp").forward(servletRequest, servletResponse);
            return;
        }else{
    
    
            //登陆了,可以访问目标资源
            filterChain.doFilter(servletRequest, servletResponse);
        }
    }

    @Override
    public void destroy() {
    
    

    }
}

在这里插入图片描述

003-完整的用户登录和权限检查

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

以下代码也必须使用javax.servlet.*
否则web-xml中的servlet-class会报错

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

输出到页面上避免中文乱码,必须写到代码最上方:
    resp.setContentType("text/html;charset=UTF-8");

004-Filter的生命周期

在这里插入图片描述

005-FilterConfig类介绍

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

006-FilterChain 过滤器链

在这里插入图片描述
在这里插入图片描述

如果Filter2中,没有Filterchain.doFilter(),会直接执行后置代码2,不会到目标资源。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

007-Filter 的拦截路径

在这里插入图片描述

后缀名匹配:后缀名可以随便写,写 .abc 也可以
只要在
<filter-mapping>
    <filter-name>Filter2</filter-name>
    <url-pattern>target.abc</url-pattern>
</filter-mapping>

地址栏写target.abc就可以访问到

猜你喜欢

转载自blog.csdn.net/m0_52041525/article/details/123777013