彼方尚有荣光在|

_xiaolin

园龄:2年9个月粉丝:3关注:5

书城项目

书城项目

第一阶段:表单验证

验证用户名:必须由字母,数字下划线组成,并且长度在5-12位

验证密码:必须由字母,数字下划线组成,并且长度为5-12位

验证确认密码:和密码相同

邮箱验证:xxxxx@xxx.com

验证码:现在只需要验证用户已输入,因为还没将到服务器,验证码生成。

1、新建一个模块

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

<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();
//去掉验证码前后空格
codeText = $.trim(codeText);
if(codeText==null ||codeText=="" ){
$("span.errorMsg").text("验证码不能为空!")
return false;
}
$("span.errorMsg").text("");
});
});

第二阶段:用户注册和登录

1、JavaEE项目的三层架构

image-20220529164445452

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

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

2、编码环节

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

image-20220529170018530

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@qq.com');
select * from t_user;

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

package com.lxg.domain;
public class User {
private Integer id;
private String username;
private String password;
private String email;
public Integer getId() {
return id;
}
public void setId(Integer 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 + '\'' +
'}';
}
public User(Integer id, String username, String password, String email) {
this.id = id;
this.username = username;
this.password = password;
this.email = email;
}
public User() {
}
}

3、编写工具类JdbcUtils

package com.lxg.utils;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidDataSourceFactory;
import java.io.InputStream;
import java.sql.Connection;
import java.util.Properties;
public class JdbcUtils {
private static DruidDataSource dataSource;
static {
try{
Properties properties = new Properties();
//读取jdbc.properties属性配置文件
InputStream inputStream = JdbcUtils.class.getClassLoader().getResourceAsStream("jdbc.properties");
//从流中读取数据
properties.load(inputStream);
//创建数据库连接池
dataSource = (DruidDataSource) DruidDataSourceFactory.createDataSource(properties);
}catch (Exception e){
e.printStackTrace();
}
}
/**
* 获取数据库连接池中的连接
* @return 如果返回null说明获取连接失败,反之成功
*/
public static Connection getConnection(){
Connection conn =null;
try{
conn = dataSource.getConnection();
}catch (Exception e){
e.printStackTrace();
}
return conn;
}
/**
* 关闭连接,返回数据库连接池
* @param conn
*/
public static void close(Connection conn){
if(conn!=null){
try{
conn.close();
}catch (Exception e){
e.printStackTrace();
}
}
}
}

测试

@Test
public void testJdbcUtils(){
for (int i = 0; i < 100; i++) {
Connection connection = JdbcUtils.getConnection();
System.out.println(connection);
JdbcUtils.close(connection);
}
}

4、编写BaseDao

package com.lxg.dao;
import com.lxg.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;
public abstract class BaseDao {
//使用DBUtils操作数据库
private QueryRunner queryRunner = new QueryRunner();
/**
* update()方法用来执行:Insert\update\Delete语句
* @param sql
* @param args
* @return如果返回-1,说明执行失败,其他表示影响的行数
*/
public int update(String sql,Object...args){
Connection connection = JdbcUtils.getConnection();
try{
return queryRunner.update(connection,sql,args);
}catch (Exception e){
e.printStackTrace();
}finally {
JdbcUtils.close(connection);
}
return -1;
}
/**
* 查询返回一个javaBean的sql语句
* @param type 返回的对象类型
* @param sql 执行的sql语句
* @param args sql对应的参数值
* @param <T> 返回的类型的泛型
* @return
*/
public<T> T queryForOne(Class<T> type,String sql,Object...args){
Connection connection = JdbcUtils.getConnection();
try {
return queryRunner.query(connection,sql,new BeanHandler<T>(type),args);
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtils.close(connection);
}
return null;
}
/**
* 查询返回多个javaBean的sql语句
* @param type 返回的对象类型
* @param sql 执行的sql语句
* @param args sql对应的参数值
* @param <T> 返回的类型的泛型
* @return
*/
public <T> List<T> queryForList(Class<T> type,String sql,Object...args){
Connection connection = JdbcUtils.getConnection();
try {
return queryRunner.query(connection,sql,new BeanListHandler<T>(type),args);
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtils.close(connection);
}
return null;
}
/**
* 执行返回一行一列的sql语句
* @param sql 执行的sql语句
* @param args sql对应的参数值
* @return
*/
public Object queryForSingleValue(String sql,Object...args){
Connection connection = JdbcUtils.getConnection();
try {
queryRunner.query(connection,sql,new ScalarHandler(),args);
} catch (SQLException e) {
e.printStackTrace();
}finally {
JdbcUtils.close(connection);
}
return null;
}
}

5、编写UserDao和测试

package com.lxg.test;
import com.lxg.dao.UserDao;
import com.lxg.dao.impl.UserDaoImpl;
import com.lxg.domain.User;
import org.junit.Test;
import static org.junit.Assert.*;
public class UserDaoTest {
UserDao userDao = new UserDaoImpl();
@Test
public void queryUserByUsername() {
if(userDao.queryUserByUsername("admin")==null){
System.out.println("用户名可用");
}else{
System.out.println("用户名已存在");
}
}
@Test
public void queryUserByUsernameAndPassword() {
if(userDao.queryUserByUsernameAndPassword("admin","123456")==null){
System.out.println("用户名或密码错误");
}else{
System.out.println("登录成功");
}
}
@Test
public void saveUser() {
System.out.println(userDao.saveUser(new User(null,"lxg","123456","xiaolin@qq.com")));
}
}

6、编写UserService和测试

package com.lxg.test;
import com.lxg.domain.User;
import com.lxg.service.UserService;
import com.lxg.service.impl.UserServiceImpl;
import org.junit.Test;
import static org.junit.Assert.*;
public class UserServiceTest {
UserService userService = new UserServiceImpl();
@Test
public void registUser() {
userService.registUser(new User(null,"zs","123456","zs@qq.com"));
userService.registUser(new User(null,"ls","123456","ls@qq.com"));
}
@Test
public void login() {
System.out.println(userService.login(new User(null,"zs","123456",null)));
}
@Test
public void existsUsername() {
if(userService.existsUsername("zs")){
System.out.println("用户名已存在");
}else {
System.out.println("用户名可用");
}
}
}

7、编写web层

1、用户注册

需求如下:
1、访问注册页面
2、填写注册信息,提交给服务器
3、服务器应该保存用户
4、当用户已经存在——提示用户注册失败,用户名已存在
5、当用户不存在——注册成功
package com.lxg.web;
import com.lxg.domain.User;
import com.lxg.service.UserService;
import com.lxg.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 RegistServlet extends HttpServlet {
private UserService userService = new UserServiceImpl();
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1、获取请求的参数
String username = req.getParameter("username");
String password = req.getParameter("password");
String email = req.getParameter("email");
String code = req.getParameter("code");
//2、检查验证码是否正确===写死,要求验证码为:abcde
if ("abcde".equalsIgnoreCase(code)) {
//正确
//3、检查用户名是否可用
if(userService.existsUsername(username)){
//用户名已存在,不可用
System.out.println("用户名["+username+"]已存在!");
req.getRequestDispatcher("/pages/user/regist.html").forward(req,resp);
}else{
//用户名可用
//调用service保存到数据库
userService.registUser(new User(null,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);
}
}
}

image-20220530131656504

2、用户登录

需求如下:
1、访问登录页面
2、填写用户名和密码后提交
3、服务器判断用户是否存在
4、如果登录失败——返回用户名或密码的错误信息
package com.lxg.web;
import com.lxg.domain.User;
import com.lxg.service.UserService;
import com.lxg.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 LoginServlet extends HttpServlet {
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、调用userService.login完成业务逻辑
User loginUser= userService.login(new User(null,username, password,null));
//如果等于null,说明登录失败
if(loginUser==null){
//3、跳转到登录页面
req.getRequestDispatcher("/pages/user/login.html").forward(req,resp);
}else {
//4、登录成功,跳转到登录成功页面
req.getRequestDispatcher("/pages/user/login_success.html").forward(req,resp);
}
}
}

image-20220530151801912

3、IDEA中的Debug调试的使用

Debug调试代码,首先需要两个元素:断点+Debug启动服务器
1、断点:只需要在代码需要停的行的左边上单击,就可以添加和取消
2Debug服务器启动Tomcat运行代码:点击调试按钮

测试工具栏:

image-20220530150050479

变量窗口,它可以查看当前方法范围内所有有效变量

image-20220530150253835

方法调用窗口

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

image-20220530151128323

其他常用调试相关按钮:

image-20220530151052023

第三阶段:优化

a:页面jsp动态化

  1. 在html页面顶行添加page指令
  2. 修改文件后缀名为:.jsp

image-20220727095851177

3.使用idea搜索替换.html为.jsp

​ CTRL+SHIF+R:或者CTRL+R

image-20220727102237773

b:抽取页面相同的内容

image-20220727113253546

c:登录,注册错误提示以及表单回显

在Servlet后端代码中将用户信息保存进域对象,

在jsp前端页面代码中使用EL表达式获取信息并显示

d:BaseServlet的抽取

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

LoginServlet和RegistServle优化为UserServlet:

package main.java.com.lxg.web;
import main.java.com.lxg.domain.User;
import main.java.com.lxg.service.UserService;
import main.java.com.lxg.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();
/**
* 处理登录功能
*
* @param req
* @param resp
* @throws ServletException
* @throws IOException
*/
protected void login(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//System.out.println("处理登录的需求");
// 1、获取请求的参数
String username = req.getParameter("username");
String password = req.getParameter("password");
// 调用 userService.login()登录处理业务
User loginUser = userService.login(new User(null, username, password, null));
// 如果等于null,说明登录 失败!
if (loginUser == null) {
// 把错误信息,和回显的表单项信息,保存到Request域中
req.setAttribute("msg", "用户或密码错误!");
req.setAttribute("username", username);
// 跳回登录页面
req.getRequestDispatcher("/pages/user/login.jsp").forward(req, resp);
} else {
// 登录 成功
//跳到成功页面login_success.html
req.getRequestDispatcher("/pages/user/login_success.jsp").forward(req, resp);
}
}
/**
* 处理注册功能
*
* @param req
* @param resp
* @throws ServletException
* @throws IOException
*/
protected void regist(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
// 1、获取请求的参数
String username = req.getParameter("username");
String password = req.getParameter("password");
String email = req.getParameter("email");
String code = req.getParameter("code");
//2、检查 验证码是否正确 === 写死,要求验证码为:abcde
if ("abcde".equalsIgnoreCase(code)) {
//3、检查 用户名是否可用
if (userService.existsUsername(username)) {
System.out.println("用户名[" + username + "]已存在!");
// 把回显信息,保存到Request域中
req.setAttribute("msg", "用户名已存在!!");
req.setAttribute("username", username);
req.setAttribute("email", email);
//跳回注册页面
req.getRequestDispatcher("/pages/user/regist.jsp").forward(req, resp);
} else {
//可用
//调用Sservice保存到数据库
userService.registUser(new User(null, username, password, email));
//跳到注册成功页面 regist_success.jsp
req.getRequestDispatcher("/pages/user/regist_success.jsp").forward(req, resp);
}
} else {
// 把回显信息,保存到Request域中
req.setAttribute("msg", "验证码错误!!");
req.setAttribute("username", username);
req.setAttribute("email", email);
System.out.println("验证码[" + code + "]错误");
req.getRequestDispatcher("/pages/user/regist.jsp").forward(req, resp);
}
}
@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 ("regist".equals(action)) {
regist(req, resp);
}
}
}

doPost还可以继续优化为:

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

如若系统又有其他模块,这个代码可以抽取出来变成BaseServlet

image-20220727151734603

e:数据的封装和抽取BeanUtils的使用

  1. BeanUtils工具类,它可以一次性的把请求的参数注入到javaBean中。

  2. BeanUtils不是jdk的类,是第三方的工具类,所以需要导包

    • 导入需要的jar包:

      commons-beanutils-1.8.0.jar
      commons-logging-1.1.1.jar

    • 使用BeanUti类方法实现注入

package main.java.com.lxg.utils;
import org.apache.commons.beanutils.BeanUtils;
import java.util.Map;
public class WebUtils {
/**
* 把Map中的值注入到对应的JavaBean属性中。
* @param value
* @param bean
*/
public static <T> T copyParamToBean(Map value, T bean){
try {
System.out.println("注入之前:"+bean);
/**
* 把所有请求的参数全都注入到user对象中
*/
BeanUtils.populate(bean,value);
System.out.println("注入之后:"+bean);
} catch (Exception e) {
e.printStackTrace();
}
return bean;
}
}
//给参数注入值
User user = WebUtils.copyParamToBean(req.getParameterMap(),new User());

CTRL+ALT+T快捷键:

image-20220727153330167

第四阶段:使用EL表达式修改表单回显(上面已修改)

第五阶段:图书模块

1、MVC概念

MVC全称:Model模型、View视图、Controller控制器
MVC最早出现在JavaEE三层的web层,它可以有效的指导web层的代码如何有效分离,单独工作
View视图:只负责数据和界面的显示,不接受任何域显示数据无关的代码,便于程序员和美工的分工合作---jsp/Html
Controller控制器:只负责接收请求,调用业务层的代码请求,然后派发页面,是一个“调度者”的角色--Servlet。转到某个页面,或者是重定向到某个页面。
Model模型:将与业务逻辑相关的数据封装成为具体的JavaBean类,其中不掺杂任何与数据处理相关的代码--JavaBean、domain、entity。
MVC是一种思想
MVC的理念是将软件代码拆分成为组件,单独开发,组合使用(目的还是为了解耦合)。

image-20220727162733181

MVC的作用还是为了降低耦合,让代码合理分层,方便后期升级和维护。

2、图书模块

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

2.2、编写图书模块的JavaBean

package main.java.com.lxg.domain;
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() {
}
@Override
public String toString() {
return "Book{" +
"id=" + id +
", name='" + name + '\'' +
", author='" + author + '\'' +
", price=" + price +
", sales=" + sales +
", stock=" + stock +
", 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;
}
}
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;
}
}
}

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

package main.java.com.lxg.dao;
import main.java.com.lxg.domain.Book;
import java.util.List;
public interface BookDao {
public int addBook(Book book);
public int deleteBookById(Integer id);
public int updateBook(Book book);
public Book queryBookById(Integer id);
public List<Book> queryBooks();
}
package main.java.com.lxg.dao.impl;
import main.java.com.lxg.dao.BookDao;
import main.java.com.lxg.domain.Book;
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`) \n" +
"values(?,?,?,?,?,?)";
return update(sql,book.getName(),book.getAuthor(),book.getPrice(),book.getSales(),book.getStock(),book.getImgPath());
}
@Override
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
public Book queryBookById(Integer id) {
String sql = "select `id` , `name` , `author` , `price` , `sales` , `stock` , `img_path` imPath 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` from t_book";
return queryForList(Book.class,sql);
}
}

生成测试快捷键:CTRL+SHIFT+T

image-20220727211721560

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

package main.java.com.lxg.service;
import main.java.com.lxg.domain.Book;
import java.util.List;
public interface BookService {
public void addBook(Book book);
public void deleteBookById(Integer id);
public void updateBook(Book book);
public Book findBookById(Integer id);
public List<Book> findAllBooks();
}
package main.java.com.lxg.service.impl;
import main.java.com.lxg.dao.BookDao;
import main.java.com.lxg.dao.impl.BookDaoImpl;
import main.java.com.lxg.domain.Book;
import main.java.com.lxg.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
public void deleteBookById(Integer id) {
bookDao.deleteBookById(id);
}
@Override
public void updateBook(Book book) {
bookDao.updateBook(book);
}
@Override
public Book findBookById(Integer id) {
return bookDao.queryBookById(id);
}
@Override
public List<Book> findAllBooks() {
return bookDao.queryBooks();
}
}

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

BookServlet:

package main.java.com.lxg.web;
import main.java.com.lxg.domain.Book;
import main.java.com.lxg.service.BookService;
import main.java.com.lxg.service.impl.BookServiceImpl;
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 add(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
}
protected void delete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
}
protected void update(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
}
protected void list(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1、通过BookService查询全部图书
List<Book> books = bookService.findAllBooks();
//2、把全部图书信息保存到Req域中
req.setAttribute("books",books);
//3、请求转发到pages/manager/book_manager.jsp页面
req.getRequestDispatcher("/pages/manager/book_manager.jsp").forward(req,resp);
}
}

需要给BaseServlet加上doGet方法才可处理get请求

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

实现展示所有图书功能:

使用jstl标签遍历获取数据显示在前端页面:

<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>

前后台的介绍:

image-20220728005100936

实现添加图书功能:

image-20220728010044419

请求转发定位到工程目录

请求重定向定位到端口号

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

实现图书删除功能:

image-20220728085541748

<script type="text/javascript">
$(function (){
//给删除的a标签绑定单击事件
$("a.deleteClass").click(function () {
//在事件的function函数中,有一个this对象,这个this对象,是当前正在响应事件的dom对象
/**
* confirm是确认提示框函数
* 参数是它提示的内容
* 它有两个按钮,一个确定,一个是取消
* 返回true表示点击了确定,返回false表示点击了取消
*/
return confirm("你确定要删除【"+$(this).parent().parent().find("td:first").text()+"】?");
})
});
</script>
protected void delete(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1、获取请求的参数id,图书编号
int id = WebUtils.parseInt(req.getParameter("id"),0);
//2、调用BookService.deleteBookById(id);
bookService.deleteBookById(id);
//3、重定向会图书列表管理页面
resp.sendRedirect(req.getContextPath()+"/manager/bookServlet?action=list");
}
<td><a class="deleteClass" href="manager/bookServlet?action=delete&id=${book.id}">删除</a></td>

实现图书修改功能:

获取前端页面数据:

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.findBookById(id);
//3、保存图书信息到request域中
req.setAttribute("book",book);
//4、请求转发到,pages/maanger/book_edit.jsp页面
req.getRequestDispatcher("/pages/manager/book_edit.jsp").forward(req,resp);
}

回显数据:

<tr>
<td><input name="name" type="text" value="${book.name}"/></td>
<td><input name="price" type="text" value="${book.price}"/></td>
<td><input name="author" type="text" value="${book.author}"/></td>
<td><input name="sales" type="text" value="${book.sales}"/></td>
<td><input name="stock" type="text" value="${book.stock}"/></td>
<td><input type="submit" value="提交"/></td>
</tr>

保存修改:

image-20220728093806524

<%--<input type="hidden" name="action" value="${param.method}">--%>
<%--<input type="hidden" name="action" value="${empty param.id ? "add" : "update"}">--%>
<input type="hidden" name="action" value="${empty requestScope.book ? "add" : "update"}">
<%--<td><a href="pages/manager/book_edit.jsp?method=add">添加图书</a></td>--%>
<td><a href="pages/manager/book_edit.jsp">添加图书</a></td>
<%--<td><a href="manager/bookServlet?action=getBook&id=${book.id}&method=update">修改</a></td>--%>
<td><a href="manager/bookServlet?action=getBook&id=${book.id}">修改</a></td
protected void update(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
//1、获取请求的参数==封装成Book对象
Book book = WebUtils.copyParamToBean(req.getParameterMap(),new Book());
//2、调用BookService.updateBook(book);修改图书
bookService.updateBook(book);
//3、重定向会图书列表管理页面
resp.sendRedirect(req.getContextPath()+"/manager/bookServlet?action=list");
}

3、图书分页

image-20220728101245611

  1. 分页功能分析

  2. 分页模型Page对象的创建

  3. 分页初步实现

  4. 首页,上一页,末页的实现

  5. 跳转到指定页码的功能

  6. 数据边界有效的检验

  7. 分页条页码的显示(显示5个连续的页码,而且当前页码在中间,除了当前页码之外,每个页码都可以点击跳转到相应的指定页面

    image-20220728151311069

    image-20220728151639039

  8. 修改分页对原来添加修改删除功能的影响

4、前台分页

<%@ 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>
<div>
<a href="pages/user/login.jsp">登录</a> |
<a href="pages/user/regist.jsp">注册</a> &nbsp;&nbsp;
<a href="pages/cart/cart.jsp">购物车</a>
<a href="pages/manager/manager.jsp">后台管理</a>
</div>
</div>
<div id="main">
<div id="book">
<div class="book_cond">
<form action="" method="get">
价格:<input id="min" type="text" name="min" value=""> 元 -
<input id="max" type="text" name="max" value=""> 元
<input type="submit" value="查询" />
</form>
</div>
<div style="text-align: center">
<span>您的购物车中有3件商品</span>
<div>
您刚刚将<span style="color: red">时间简史</span>加入到了购物车中
</div>
</div>
<c:forEach items="${requestScope.page.items}" var="book" >
<div class="b_list">
<div class="img_div">
<img class="book_img" alt="" src="${book.imgPath}" />
</div>
<div class="book_info">
<div class="book_name">
<span class="sp1">书名:</span>
<span class="sp2">${book.name}</span>
</div>
<div class="book_author">
<span class="sp1">作者:</span>
<span class="sp2">${book.author}</span>
</div>
<div class="book_price">
<span class="sp1">价格:</span>
<span class="sp2">¥${book.price}</span>
</div>
<div class="book_sales">
<span class="sp1">销量:</span>
<span class="sp2">${book.sales}</span>
</div>
<div class="book_amount">
<span class="sp1">库存:</span>
<span class="sp2">${book.stock}</span>
</div>
<div class="book_add">
<button>加入购物车</button>
</div>
</div>
</div>
</c:forEach>
</div>
<div id="page_nav">
<%--大于首页才显示--%>
<c:if test="${requestScope.page.pageNo>1}">
<a href="client/bookServlet?action=page&pageNo=1">首页</a>
<a href="client/bookServlet?action=page&pageNo=${requestScope.page.pageNo-1}">上一页</a>
</c:if>
<%--页码输出的开始--%>
<c:choose>
<%--1、总页码小于等于五,页码范围1-总页码--%>
<c:when test="${requestScope.page.pageTotal<=5}">
<c:set var="begin" value="1"/>
<c:set var="end" value="${requestScope.page.pageTotal}"/>
</c:when>
<%--2、总页码大于五--%>
<c:when test="${requestScope.page.pageTotal>5}">
<c:choose>
<%--2.1当前页码为前面三个,1,2,3的情况-,页码范围为15--%>
<c:when test="${requestScope.page.pageNo <=3}">
<c:set var="begin" value="1"/>
<c:set var="end" value="5"/>
</c:when>
<%--2.2当前页码为最后三个,页码范围为总页码减4到总页码--%>
<c:when test="${requestScope.page.pageNo>requestScope.page.pageTotal-3}">
<c:set var="begin" value="${requestScope.page.pageTotal-4}"/>
<c:set var="end" value="${requestScope.page.pageTotal}"/>
</c:when>
<%--2.3:剩下的页码--%>
<c:otherwise>
<c:set var="begin" value="${requestScope.page.pageNo-2}"/>
<c:set var="end" value="${requestScope.page.pageNo+2}"/>
</c:otherwise>
</c:choose>
</c:when>
</c:choose>
<c:forEach begin="${begin}" end="${end}" var="i">
<c:if test="${i==requestScope.page.pageNo}">
【${i}】
</c:if>
<c:if test="${i!=requestScope.page.pageNo}">
<a href="client/bookServlet?action=page&pageNo=${i}">${i}</a>
</c:if>
</c:forEach>
<%--页码输出的结束--%>
<%--如果已经是最后一页,则不显示下一页和末页--%>
<c:if test="${requestScope.page.pageNo < requestScope.page.pageTotal}">
<a href="client/bookServlet?action=page&pageNo=${requestScope.page.pageNo+1}">下一页</a>
<a href="client/bookServlet?action=page&pageNo=${requestScope.page.pageTotal}">末页</a>
</c:if>
共${requestScope.page.pageTotal}页,${requestScope.page.pageTotalCount}条记录
到第<input value="${param.pageNo}" name="pn" id="pn_input"/>页
<input id="searchPageBtn" type="button" value="确定">
<script type="text/javascript">
$(function (){
//跳到指定的页码
$("#searchPageBtn").click(function (){
var pageNo = $("#pn_input").val();
//js语言提供了一个location地址栏对象
//它有一个属性叫href,它可以获取浏览器地址栏中的地址
location.href="${pageScope.basePath}client/bookServlet?action=page&pageNo="+pageNo;
});
});
</script>
</div>
</div>
<%--静态包含页脚内容--%>
<%@include file="/pages/common/footer.jsp"%>
</body>
</html>

根据价格区间查询数据并分页:

image-20220729004000962

第六阶段:登录登出

1、登录

a、显示用户名

2、登出

a、注销用户

1、销毁session中用户登录的信息(或者销毁session)

2、重定向到首页或者登录界面

3、表单重复提交

有三种常见情况:

1、提交完表单,服务器使用请求转发来进行页面跳转,这个时候用户按下F5功能键,就会发起最后一次的请求,造成表单重复提交问题。
解决方法是使用重定向来进行页面跳转
2、用户正常提交服务器,但是由于网络延迟等原因,迟迟未收到服务器的响应,这个时候,用户以为提交失败,就会着急,然后多点了几次提交操作,也会造成表单重复提交
3、用户正常提交服务器,服务器也没有延迟,但是提交完成之后,用户回退浏览器,重新提交,也会造成表单重复提交
后两种因没有可直接解决的方法,后引入验证码,使用验证码防止用户恶意提交

a、验证码

验证码解决表单重复提交的底层原理

image-20220729143942364

b、谷歌kaptcha图片验证码的使用

使用步骤如下:

1、导入谷歌验证码的jar包(kaptcha-2.3.2.jar)
2、在web.xml中去配置用于生成验证码的Servlet程序
<servlet>
<servlet-name>KaptchaServlet</servlet-name>
<servlet-class>com.google.code.kaptcha.servlet.KaptchaServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>KaptchaServlet</servlet-name>
<url-pattern>/kaptcha.jpg</url-pattern>
</servlet-mapping>
3、在表单中使用img标签去显示验证码图片并使用它
验证码:<input type="text" style="width: 50px; " name="code">
<img src="http://localhost:8080/bookTest/kaptcha.jpg" style="width:110px;height: 20px; " alt=""><br/>
4、在服务器获取谷歌生成的验证码,和客户端发送过来的验证码比较使用

image-20220729155029866

4、购物车模块

image-20220729163403162

1、编写购物车模型

2、加入购物车功能的实现

3、购物车的展示

4、删除购物车商品项的功能

5、清空购物车

6、修改商品数量

image-20220730093854413

7、加入购物车提醒功能

5、订单模块

image-20220730105054765

1、创建数据库表

2、编写对应实体类

3、编写dao和测试dao

4、编写service和测试service

5、配置web.xml

6、编写OrderServlet

7、修改页面

第七阶段:权限检查

1、使用过滤器拦截

2、ThreadLocal的使用

它可以解决多线程的数据安全问题
ThreadLocal它可以给当前线程关联一个数据(可以是普通变量,可以是对象,也可以是数据,集合)
特点:
1ThreadLocal可以为当前线程关联一个数据(它可以是像Map一样存储数据,key为当前线程)
2、每一个ThreadLocal对象,只能为当前线程关联一个数据,如果要为当前线程关联多个数据,就需要使用多个ThreadLocal对象实例
3、每个ThreadLocal对象实例定义的时候一般都是static类型
4ThreadLocal中保存数据,在线程销毁后,会由JVM虚拟自动释放

image-20220730232955020

3、使用Filter和ThreadLocal组合管理事务

image-20220730235730414

1、使用ThreadLocal确保所有操作对象都使用同一个连接对象

2、使用Filter统一给所有Service方法都加上try—catch,来实现事物的管理

image-20220731002743596

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

在web.xml配置错误页面跳转

第八阶段:AJAx

1、使用Ajax验证用户名是否可用

image-20220731010421892

2、使用ajax修改加入购物车功能

第九阶段:

1、库存问题

2、其他模块

var msg = $(this).attr('orderMsg');
alert(msg);

本文作者:_xiaolin

本文链接:https://www.cnblogs.com/SilverStar/p/17415192.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   _xiaolin  阅读(52)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起