文章目录

  • 十四、书城项目第三阶段——优化
    • (1)页面jsp动态化
    • (2)抽取页面中相同的内容
      • A.登录成功的菜单
      • B.base、css、jQuery标签
      • C.每个页面的页脚
      • D.manager模块的菜单
    • (3)登录、注册错误提示和表单回显
    • (4)BaseServlet的抽取
      • A. 代码优化:合并 LoginServlet 和 RegistServlet 程序为 UserServlet
      • B. 优化代码二:使用反射优化大量 else if
      • C. 代码优化三:抽取 BaseServlet 程序
    • (5)数据的封装和抽取BeanUtils的使用
  • 十五、书城项目第四阶段——使用EL表达式修改表单回显
  • 十六、书城项目第五阶段——编写图书模块
    • 001-MVC概念
    • 002-编写图书模块的数据库表
    • 003-编写图书模块的JavaBean
    • 004-编写图书模块的Dao和测试Dao
    • 005-编写图书模块的Service和测试Service
    • 006-编写图书模块的Web层和页面联调测试
      • (1)实现获取图书信息功能
      • (2)实现添加图书功能
      • (3)实现删除图书的功能
      • (4)实现修改图书功能
  • 十六、书城项目第五阶段——分页
  • 十七、Cookie
    • 001-什么是 Cookie?
    • 002-如何创建 Cookie?
    • 003-服务器如何获取 Cookie?
    • 004-Cookie 值的修改
    • 005-浏览器查看 Cookie
    • 006-Cookie 生命控制
    • 007-Cookie 有效路径 Path 的设置
    • 008-Cookie 练习---免输入用户名登录
  • 十八、Session
    • 001-什么是Session会话
    • 002-如何创建和获取Session
    • 003-Session域数据的存储和获取
    • 004-Session生命周期控制
    • 005-浏览器和 Session 之间是怎么关联的?
  • 十九、书城项目第六阶段
  • 二十、书城项目第七阶段
  • 二十一、Filter 过滤器
    • 001-什么是Filter 过滤器?
    • 002-基本使用示例
    • 003-完整的用户登录和权限检查
    • 004-Filter的生命周期
    • 005-FilterConfig类介绍
    • 006-FilterChain 过滤器链
    • 007-Filter 的拦截路径

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

(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目录选pagesReplace All 全部替换

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

A.登录成功的菜单

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

在pages目录下,创建一个common目录在common目录下创建 login_success_menu.jsp 然后将上面的登录成功的菜单代码写进该jsplogin_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.jspreq.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);}}@Overrideprotected 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,并继承HttpServletUserServlet和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 {@Overrideprotected 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;}}@Overridepublic 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();@Testvoid addBook() {bookDao.addBook(new Book(null,"国哥为什么这么帅!", "191125", new BigDecimal(9999),1100000,0,null));}@Testvoid deleteBookById() {bookDao.deleteBookById(21);}@Testvoid updateBook() {bookDao.updateBook(new Book(21,"大家都可以这么帅!", "国哥", new BigDecimal(9999),1100000,0,null));}@Testvoid queryBookById() {System.out.println( bookDao.queryBookById(21) );}@Testvoid 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();@Testvoid addBook() {bookService.addBook(new Book(null,"国哥在手,天下我有!", "1125", new BigDecimal(1000000),100000000, 0, null));}@Testvoid deleteBookById() {bookService.deleteBookById(22);}@Testvoid updateBook() {bookService.updateBook(new Book(22,"社会我国哥,人狠话不多!", "1125", new BigDecimal(999999),10, 111110, null));}@Testvoid queryBookById() {System.out.println(bookService.queryBookById(22));}@Testvoid 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也就没了,要创建一个新的sessionSession 技术,底层其实是基于 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 {@Overridepublic 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);}}@Overridepublic 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就可以访问到

JavaWeb学习笔记(5)-B站尚硅谷相关推荐

  1. JVM学习笔记汇总:结合尚硅谷宋红康老师视频教程及PPT

    JVM学习笔记汇总:结合尚硅谷宋红康老师视频教程及PPT 第一章:JVM虚拟机的介绍 1.1虚拟机的分类 虚拟机通常分为两类:系统虚拟机和程序虚机.其中,系统虚拟机是指完全对物理计算机的仿真,而程序虚 ...

  2. HTMLCSS学习笔记 纯知识点版 (尚硅谷2019李立超版)

    此版为纯知识点无练习笔记版本 目录 1. HTML基础 1.1 网页的结构 1.2 HTML中的"实体" 1.3 meta 标签 1.4 语义化标签 1.7 列表 1.8 超链接 ...

  3. 1.Spring学习笔记_HelloWorld(by尚硅谷_佟刚)

    一.Spring是什么 Spring 是一个开源框架. Spring 为简化企业级应用开发而生(主要针对EJB2来说),使用 Spring 可以使简单的 JavaBean 实现以前只有 EJB 才能实 ...

  4. JDBC学习笔记(1)---B站尚硅谷宋红康

    JDBC学习笔记(1)-B站尚硅谷宋红康 JDBC学习笔记(2)-B站尚硅谷宋红康 文章目录 软件架构方式介绍 JavaWeb技术概览 第1章:JDBC概述 1.1 数据的持久化 1.2 Java中的 ...

  5. b站尚硅谷springmvc学习视频:springmvc文档

    文章目录 一.SpringMVC简介 (b站尚硅谷springmvc学习视频:springmvc文档) 1.什么是MVC 2.什么是SpringMVC 3.SpringMVC的特点 二.HelloWo ...

  6. B站狂神说JavaWeb学习笔记

    JavaWeb学习笔记(根据b站狂神说java编写) 1.基本概念 1.1 前言 静态Web: 提供给所有人看数据不会发生变化! HTML,CSS 动态Web: 有数据交互,登录账号密码,网站访问人数 ...

  7. Javaweb学习笔记(一)

    目录 1.Html 和 Css 1.1.B/S 软件的结构 1.2.网页的组成部分 1.3.HTML简介 1.4.HTML文件的书写规范 1.5.HTML标签 1.6.标签的语法 1.7.常用标签 1 ...

  8. JavaWeb学习笔记2 —— Web服务器简介

    JavaWeb学习笔记2 -- Web服务器简介 参考教程B站狂神https://www.bilibili.com/video/BV12J411M7Sj 相关技术 ASP: 微软:国内最早流行的就是A ...

  9. Redis个人学习笔记 参考B站视频以及CSDN文档 2万多字 非常全面

    参考内容: B站尚硅谷Redis视频教程 <Redis 6 入门到精通 超详细 教程> B张黑马程序员Redis视频教程 <黑马程序员Redis入门到实战教程,全面透析redis底层 ...

最新文章

  1. Spring Initializr 构建Spring Boot/Cloud工程
  2. 鄙人为啥要在博客上记录学到的技术细节?
  3. Loadrunner脚本学习总结
  4. postgresql 子查询_PostgreSQL子事务及性能分析
  5. iOS开发UIlabel篇:iOS 10 3 Label设置的中划线突然失效了
  6. 实现ARM——Linux的自动登录
  7. android进程(关闭自己和关闭其他进程)
  8. c语言 指正判断字符串大小
  9. hive 导出json格式 文件_Magicodes.IE在.NET Core中通过请求头导出多种格式文件
  10. Linux 系统之Sysvinit
  11. 游戏角色坐标的保存间隔_游戏岗位看这里鸭——
  12. 笔记72 高级SSM整合
  13. 计蒜客2019蓝桥杯省赛 B 组模拟赛(一)轻重搭配|
  14. 这些硬核公众号你知道几个?
  15. mysql可以建立个人数据库吗_mysql怎么建立数据库?
  16. cad字体安装_1.1.2 CAD篇之字体库设置
  17. 图像的旋转,imrotate函数的应用
  18. HbuiderX调用微信开发者工具设置
  19. 通俗易懂去讲解反射(Reflect)
  20. 一曲罢已,愁若梨花,乱红释怀,浮躁尽然。。。。。。

热门文章

  1. 我们既然选择了远方,便只顾风雨兼程)
  2. 贴片陶瓷电容材质NPO、C0G、X7R、X5R、Y5V、Z5U区别
  3. 02-JVM堆里面的分区:Eden,survival (from+ to),老年代,各自的特点?
  4. leetcode中数组问题常用的处理方式
  5. Django 模型操作
  6. 2022年电脑行业前景
  7. 9.27通则康威技术面
  8. 揭秘奥运会四大难解之谜
  9. Diango:Django基础
  10. 什么是最好的UML在线免费软件