首页 > 其他分享 >书城项目

书城项目

时间:2023-05-19 15:12:21浏览次数:30  
标签:项目 req lxg book import com public 书城

书城项目

第一阶段:表单验证

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

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

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

邮箱验证:[email protected]

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

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;
         }
         // 邮箱验证:[email protected]
         //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','[email protected]');

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","[email protected]")));
    }
}

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","[email protected]"));
        userService.registUser(new User(null,"ls","123456","[email protected]"));
    }

    @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、断点:只需要在代码需要停的行的左边上单击,就可以添加和取消
2、Debug服务器启动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的情况-,页码范围为1到5--%>
                    <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它可以给当前线程关联一个数据(可以是普通变量,可以是对象,也可以是数据,集合)
特点:
1、ThreadLocal可以为当前线程关联一个数据(它可以是像Map一样存储数据,key为当前线程)
2、每一个ThreadLocal对象,只能为当前线程关联一个数据,如果要为当前线程关联多个数据,就需要使用多个ThreadLocal对象实例
3、每个ThreadLocal对象实例定义的时候一般都是static类型
4、ThreadLocal中保存数据,在线程销毁后,会由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);

标签:项目,req,lxg,book,import,com,public,书城
From: https://www.cnblogs.com/SilverStar/p/17415192.html

相关文章

  • 记一次前后端项目Nginx代理出现的“405”问题
    事情的起因是这样的:因为好久没有写前端代码了对前端打包部署这块有点抵触公司的有个小项目是前端vue+后端springboot实现的在部署的时候通过nginx反向代理去实现跨域(这块nginx一直都是简单的使用也没有过深的了解包括之前也用过nginx+memache实现的灰度部署的方案)总感觉很......
  • DHub Superworks自动化学习项目图纸
    分享一套 Superworks自动化设计项目图纸,包括封面,图纸目录,高层代号位置代号,原理图22张,部件汇总表,元件列表,连接列表,接线图,端子列表。下载以后打开swPro文件以打开整个项目。没有安装Superworks自动化设计的朋友可根据项目包中的readme文件安装。......
  • idea启动spingboot项目一直在build中
    在本地启动项目时,会一直build,然后就百度查了下,看了下这个帖子写的内容 https://www.cnblogs.com/tysk/p/10859594.html,反正就是重启电脑也不行,重新拉项目也不行。重启idea也不太行我的情况可能也是在springboot项目的类上写了个main方法测试,然后run运行,后面可能是进程还没退出完......
  • springboot项目引入公用项目
    <!--公共interface模块--><dependency><groupId>com.hcp</groupId><artifactId>dubbointerface</artifactId><version>0.0.1-SNAPSHOT</version></depende......
  • 在Vue2项目中遇到的问题汇总
    1问题1:Proxyerror:Couldnotproxyrequest/studentsfromlocalhost:8080tohttp://localhost:5000/.SeehtProxyerror:Couldnotproxyrequest/studentsfromlocalhost:8080tohttp://localhost:5000/.Seeht终端报错:浏览器报错这个里面给的文件没有打开,打......
  • VUE项目
    一、创建vue工程使用vue工程之前,确保已经安装了nodejs,在命令行中输入node-v可以看到node版本即可。nodejs官网下载地址http://nodejs.cn/download/current/安装vue#在cmd或pycharm的下方Terminal中执行命令npmconfigsetregistryhttps://registry.npm.taobao.org#......
  • 看模型、做技术交底、做项目汇报,这款BIM+CAD+GIS工具免费了
    现场汇报效果不好,导致丢了一个项目!项目汇报平淡无奇,方案屡次被毙!面对专家质疑,回答苍白无力!估计大家都有过这种经历和感受。详细分析一下,基本上有以下几个方面的原因:➤ 汇报的时候,找不到合适的软件做三维演示?Revit、SketchUp等建模软件不适合演示汇报,而且还缺少周边环境信息。......
  • 项目开发文档整理(很全面)
    写在前面在日常项目开发过程中,会产生大量的过程文档,比如开发过程中的文档、管理过程中的文档、产品相关文档等等,那这些文档我们日常怎么去管理呢?怎么去做规划呢?如何做成通用标准呢?小编特地整理了一整套全过程文档。获取方式q:262086839。目录01计划阶段项目信息表项目实施......
  • Spring Cloud开发实践(六): 基于Consul和Spring Cloud 2021.0的演示项目
    目录SpringCloud开发实践(一):简介和根模块SpringCloud开发实践(二):Eureka服务和接口定义SpringCloud开发实践(三):接口实现和下游调用SpringCloud开发实践(四):Docker部署SpringCloud开发实践(五):Consul-服务注册的另一个选择SpringCloud开发实践(六):基......
  • 项目拉取 问题记录
    项目拉取中的小问题rimraf无法使用1问题描述-在新设备中管理员权限下全局下载rimraf。显示在此系统禁止运行脚本2解决方法:-管理员权限进入终端,-输入set-executionpolicyremotesigned-Ynodejs版本切换版本问题1问题描述-在项目......