JavaWeb《后端内容:4. 项目实战:书城系统》

news2024/11/25 11:56:09

0.把之前的系统的Myssm部分封装为包

新建空的工件jar包

创建相同的文件夹,导入相应文件要从out里面导入字节码文件 

全部设置完后点构建工件,然后点刚刚我们设置的这个工件,然后从src下的out文件相应的位置就能找到这个jar包,用于其他项目的开发了

  

1.熟悉业务需求

1. 需求分析
2. 数据库设计
 1) 实体分析
    - 图书                    Book
    - 用户                    User
    - 订单                    OrderBean
    - 订单详情             OrderItem
    - 购物车项             CartItem
 2) 实体属性分析
    - 图书 : 书名、作者、价格、销量、库存、封面、状态
    - 用户 : 用户名、密码、邮箱
    - 订单 : 订单编号、订单日期、订单金额、订单数量、订单状态、用户
    - 订单详情 : 图书、数量、所属订单
    - 购物车项 : 图书、数量、所属用户

2.准备工作

新建module并把前端页面粘贴进去,我们不要像之前一样放到web下面,放到web-inf下面,因为放web下别人可以随便访问。静态资源还放web下

建立数据库和表


CREATE DATABASE bookdb CHAR SET utf8;
USE bookdb ;
CREATE TABLE `t_book` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `bookImg` varchar(200) NOT NULL,
  `bookName` varchar(20) DEFAULT NULL,
  `price` double(10,2) DEFAULT NULL,
  `author` varchar(20) DEFAULT NULL,
  `saleCount` int(11) DEFAULT NULL,
  `bookCount` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8;

/*Data for the table `t_book` */

insert  into `t_book`(`id`,`bookImg`,`bookName`,`price`,`author`,`saleCount`,`bookCount`) values (1,'cyuyanrumenjingdian.jpg','C语言入门经典',99.00,'亚历山大',8,197),(2,'santi.jpg','三体',48.95,'周杰伦',18,892),(3,'ailuntulingzhuan.jpg','艾伦图灵传',50.00,'刘若英',12,143),(4,'bainiangudu.jpg','百年孤独',40.00,'王力宏',3,98),(5,'biancheng.jpg','边城',30.00,'刘德华',2,99),(6,'jieyouzahuodian.jpg','解忧杂货店',27.00,'东野圭吾',5,100),(7,'zhongguozhexueshi.jpg','中国哲学史',45.00,'冯友兰',3,100),(8,'huranqiri.jpg','忽然七日',19.00,'劳伦',50,200),(9,'sudongpozhuan.jpg','苏东坡传',20.00,'林语堂',50,300),(10,'fusang.jpg','扶桑',20.00,'严歌岑',10,89),(11,'geihaizideshi.jpg','给孩子的诗',23.00,'北岛',5,99);


CREATE TABLE `t_user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `uname` varchar(20) NOT NULL,
  `pwd` varchar(32) NOT NULL,
  `email` varchar(100) DEFAULT NULL,
  `role` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `uname` (`uname`)
) ENGINE=InnoDB AUTO_INCREMENT=17 DEFAULT CHARSET=utf8;

/*Data for the table `t_user` */

insert  into `t_user`(`id`,`uname`,`pwd`,`email`,`role`) values (1,'lina','ok','lina@sina.com.cn',0),(2,'kate','ok','hello_kate@126.com',1),(3,'鸠摩智','ok','jiujiu@126.com',0),(4,'宝2021','ok','bao2021@sohu.com.cn',0),(5,'宝2022','123','bao2022@sohu.com.cn',0);



/*Table structure for table `t_cart_item` */

CREATE TABLE `t_cart_item` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `book` int(11) DEFAULT NULL,
  `buyCount` int(11) DEFAULT NULL,
  `userBean` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `FK_cart_book` (`book`),
  KEY `FK_cart_user` (`userBean`),
  CONSTRAINT `FK_cart_book` FOREIGN KEY (`book`) REFERENCES `t_book` (`id`),
  CONSTRAINT `FK_cart_user` FOREIGN KEY (`userBean`) REFERENCES `t_user` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=21 DEFAULT CHARSET=utf8;

/*Data for the table `t_cart_item` */

insert  into `t_cart_item`(`id`,`book`,`buyCount`,`userBean`) values (9,1,1,2),(10,5,1,1),(11,1,2,1),(12,2,13,1),(13,3,2,1),(14,4,1,1),(15,6,1,1),(16,7,1,1),(17,8,1,1),(18,9,1,1),(19,10,1,1),(20,11,4,1);

/*Table structure for table `t_order` */

CREATE TABLE `t_order` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `orderNo` varchar(128) NOT NULL,
  `orderDate` datetime DEFAULT NULL,
  `orderUser` int(11) DEFAULT NULL,
  `orderMoney` double(10,2) DEFAULT NULL,
  `orderStatus` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `orderNo` (`orderNo`),
  KEY `FK_order_user` (`orderUser`),
  CONSTRAINT `FK_order_user` FOREIGN KEY (`orderUser`) REFERENCES `t_user` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8;

/*Data for the table `t_order` */

insert  into `t_order`(`id`,`orderNo`,`orderDate`,`orderUser`,`orderMoney`,`orderStatus`) values (4,'5eaab6146dc54e0482fdb8b6120c229b_20211025112519','2021-10-25 11:25:20',1,506.90,0),(5,'f5a22aac925d42eabc6b49c45a3eb74f_20211025113004','2021-10-25 11:30:04',1,48.95,0),(6,'8a245df4359e4224b531cf121c4acab3_20211025113019','2021-10-25 11:30:20',1,0.00,0),(7,'b521cd49ab2943f0bbc0630c95978f1c_20211025113039','2021-10-25 11:30:40',1,48.95,0),(8,'d4f366a82cd4491c9899b181753804b4_20211025113151','2021-10-25 11:31:52',1,48.95,0),(9,'8f5869a839f4483e947bd2c3163f3c23_20211025113159','2021-10-25 11:31:59',1,48.95,0),(10,'c5fcd95dbe7f49669f96b4ad6444ae6b_20211025120531','2021-10-25 12:05:32',1,147.95,0),(11,'6240ec3e5ac04e3583e1beb75a9e94ec_20211025120542','2021-10-25 12:05:42',1,147.95,0);

/*Table structure for table `t_order_item` */

CREATE TABLE `t_order_item` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `book` int(11) DEFAULT NULL,
  `buyCount` int(11) DEFAULT NULL,
  `orderBean` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `FK_detail_book` (`book`),
  KEY `FK_detail_order` (`orderBean`),
  CONSTRAINT `FK_detail_book` FOREIGN KEY (`book`) REFERENCES `t_book` (`id`),
  CONSTRAINT `FK_detail_order` FOREIGN KEY (`orderBean`) REFERENCES `t_order` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=19 DEFAULT CHARSET=utf8;

/*Data for the table `t_order_item` */

insert  into `t_order_item`(`id`,`book`,`buyCount`,`orderBean`) values (6,1,1,4),(7,2,2,4),(8,10,1,4),(9,3,5,4),(10,4,1,4),(11,2,1,5),(12,2,1,7),(13,2,1,8),(14,2,1,9),(15,1,1,10),(16,2,1,10),(17,1,1,11),(18,2,1,11);

数据库一共五个表,第一个是 t_user(用户表)主键id(多次作为别的表的外键) 

 

第二个是 t_book(图书表)

这里老师说最好加个状态的列 

第三个是 t_cart_item(购物车项表)t_user的主键 id 为它 userBean 的外键, book的主键 id 为它 book 的外键 

 

第四个是 t_oreder(订单表)t_user的主键 id 为它 orderUser 的外键

第五个是 t_oreder_item(订单项表)(一个订单包括多个订单项,类似一个购物车包含多个购物车项)t_user的主键 id 为它 orderBean的外键,t_book的主键id为它book的外键

 

然后开始写pojo类,同时记得把druid数据库连接池的配置文件和applicationcontext.xml书写Bean的配置文件复制到src下。这里page还是需要保留的,方便我们能保证一些访问不绕开Thymeleaf或者说Servlet

<?xml version="1.0" encoding="utf-8" ?>

<!DOCTYPE beans [
        <!ELEMENT beans (bean*)>
        <!ELEMENT bean (property*)>
        <!ELEMENT property (#PCDATA)>

        <!ATTLIST bean id ID #REQUIRED>
        <!ATTLIST bean class CDATA #IMPLIED>
        <!ATTLIST property name CDATA #IMPLIED>
        <!ATTLIST property ref IDREF #IMPLIED>
        ]>

<beans>

    <bean id="page" class="com.fanxy.myssm.myspringmvc.PageController"/>
</beans>

 这里就省略构造函数和get set方法,实际是需要写的,还把一些业务上的1对多,多对一写了,并且参照我们上个项目,有对应关系的写对方类的类型属性,同时都写上带id的构造函数,以备我们改造的新的BaseDAO能直接通过反射生成对方带id的成员变量。也别忘了写空参构造函数(JavaBean基本结构,方便调用反射生成实例)

public class User {
    private Integer id;
    private String uname;
    private String pwd;
    private String email;
    private Integer role;
}

//我们应该给购物车项写一个Cart购物车类,存放一个人的购物车的购物车项的集合
public class CartItem {
    private Integer id;
    private Book book;
    private Integer buyCount;
    private User userBean;
}

public class Book {
    private Integer id;
    private String bookImg;
    private String bookName;
    private Double price;
    private String author;
    private Integer saleCount;
    private Integer bookCount;
    private Integer bookStatus = 0;
}

public class OrderItem {
    private Integer id;
    private Book book; // M : 1
    private Integer Count;
    private OrderBean orderBean; // M : 1
}

public class OrderBean {
    private Integer id;
    private String orderNo;
    private LocalDateTime orderDate;
    private User orderUser;
    private Double orderMoney;
    private Integer orderStatus;
    private List<OrderItem> orderItemList; // 1 : M
}

也别忘了把Bean的配置文件参数和Thymeleaf的上下文参数配置复制到web.xml文件,这次我们把前端页面都放在了WEB-INF下,我们干脆把index.html也放进去,然后Thymeleaf配置的前缀我们就改成现在的目录前缀,不再是以前的一个 / 

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">

    <!-- 在上下文参数中配置视图前缀和视图后缀 -->
    <context-param>
        <param-name>view-prefix</param-name>
        <param-value>/WEB-INF/pages/</param-value>
    </context-param>
    <context-param>
        <param-name>view-suffix</param-name>
        <param-value>.html</param-value>
    </context-param>

    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>applicationContext.xml</param-value>
    </context-param>
    
</web-app>

根据我们现在的登录页面的位置,我们的tomcat根据PageController的启动和渲染,我们是要经过Thymeleaf,故前缀的一部分其实Thymeleaf的配置帮我们写了,我们直接写user/login即可 

接着我们还是延续我们之前系统的思路,先去写登录页面的前端,引入Thymeleaf格式,把src能改的先改了,然后表单的action我们应该从静态页面改成/user.do,将来写UserController,其次我们表单的method写post,当然老规矩,既然是表单我们的到时候写发送逻辑的时候要遵守我们的DispatcherServlet,需要写一个隐藏域的input,name="operate",value="login",意味着将来要写用户的login方法。同时表单的登录部分的账号和密码部分的name要写的和数据库对应(uname,pwd)

很明显,下一步登录需要UserController,写它之前先写DAO层和Service层相应的结构,让我们优先完成登录模块,记得把Bean的配置写到xml里面。

<beans>
    <bean id="page" class="com.fanxy.myssm.myspringmvc.PageController"/>

    <!--  DAO   -->
    <bean id="userDAO" class="com.fanxy.dao.impl.UserDAOImpl"/>

    <!--  Service   -->
    <bean id="userService" class="com.fanxy.service.impl.UserServiceImpl">
        <property name="userDAO" ref="userDAO"/>
    </bean>

    <!--  Controller   -->
    <bean id="user" class="com.fanxy.controller.UserController">
        <property name="userService" ref="userService"/>
    </bean>

</beans>

这里先让Controller输出一下查到的用户,看看是否这部分有bug。

public interface UserDAO {
    public User getUser(String uname, String pwd);
}

public class UserDAOImpl extends BaseDao implements UserDAO {
    @Override
    public User getUser(String uname, String pwd) {
        String sql = "SELECT * FROM t_user WHERE uname = ? AND pwd = ?;";
        try {
            List<User> users = executeQuery(User.class, sql, uname, pwd);
            if (users.size() > 0) {
                return users.get(0);
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("UserDAO.getUser出错了");
        }
        return null;
    }
}

public interface UserService {
    public User login(String uname, String pwd);
}

public class UserServiceImpl implements UserService {
    private UserDAO userDAO = null;
    
    @Override
    public User login(String uname, String pwd) {
        return userDAO.getUser(uname, pwd);    
    }
}

public class UserController {
    private UserService userService = null;

    public String login(String uname, String pwd, HttpSession session){
        User user = userService.login(uname, pwd);
        System.out.println(user);
        return "index";
    }
}

经过调试发现前面无bug,下面我们要思考我们的index页面,需要显示图书列表,这些图书的信息来自数据库。所以显然我们需要写BookService层和DAO层,让我们的登录方法返回的页面是具有图书信息的,放入session作用域。

这里我们按苹果系统我们是关键字查询,还带分页,逻辑在页面处判断,需要加入参数,通过Limit分页,查询靠LIKE关键字, 这里如果我们想按价格最大值最小值是可以通过输入这两个参数,然后通过BETEEN AND这种方法查询,然后分页逻辑也一样,这里就先不做了,直接全部查询了。当然别忘了注册Bean。

public interface BookDAO {
    public List<Book> getBookList();
}

public class BookDAOImpl extends BaseDao implements BookDAO {
    @Override
    public List<Book> getBookList() {
        String sql = "SELECT * FROM t_book;";
        try {
            return executeQuery(Book.class, sql);
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException("BookDAOImpl.getBookList出错了");
        }
    }
}

public interface BookService {
    public List<Book> getBookList();
}

public class BookServiceImpl implements BookService {
    private BookDAO bookDAO = null;

    @Override
    public List<Book> getBookList() {
        return bookDAO.getBookList();
    }
}

这里我们不想让登录方法还同时把图书列表的功能给聚合,我们后台还有管理员,还有图书的管理操作,显然根据高内聚低耦合的思路,我们应该把图书管理的部分专门写Controller去负责。这里我们的redirect没有写operate=index是因为我们之前写这个模块的时候,operate为空默认赋值index了。

public class UserController {
    private UserService userService = null;

    public String login(String uname, String pwd, HttpSession session){

        User user = userService.login(uname, pwd);
        if(user != null){
            session.setAttribute("currUser", user);
            return "redirect:book.do";
        }
        return "user/login";
    }
}

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/534635.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Discourse Table Builder 插件

ABC 仓库链接GitHub - discourse/discourse-table-builder: A theme component that allows for easily building and editing of markdown tables in Discourse. 概述Table Builder 这个插件能够让用户能够在 Discourse 的编辑对话框中快速的对表格进行编辑&#xff0c;同时也…

Flink学习——处理不同数据源的流数据,存入不同的Sink端

目录 一、单机版安装 二、IDEA操作Flink (一)添加依赖 (二)数据源——Source 1.加载元素数据 2.加载集合数据 3.加载文件目录 4.加载端口 5.加载kafka的topic——重要&常用 6.加载自定义数据源 (三)输出端——Sink 1.读取文件中的数据&#xff0c;处理后输出到…

ESP32设备驱动-振动电机模块驱动

振动电机模块驱动 文章目录 振动电机模块驱动1、振动电机介绍2、硬件准备3、软件准备4、驱动实现1、振动电机介绍 振动电机是用于产生振动的机械装置。 振动的产生是在驱动轴上质量不均匀的电动机的支持下发生的。 它是一种微型直流电机,通过振动让用户知道声音。 在此必须注…

《计算机网络—自顶向下方法》 Wireshark实验(五):UDP 协议分析

用户数据报(UDP)协议是运输层提供的一种最低限度的复用/分解服务&#xff0c;可以在网络层和正确的用户即进程间传输数据。UDP 是一种不提供不必要服务的轻量级运输协议&#xff0c;除了复用/分用功能和简单的差错检测之外&#xff0c;几乎就是 IP 协议了&#xff0c;也可以说它…

RabbitMQ养成记 (10.高级特性:死信队列,延迟队列)

死信队列&#xff08;DLX&#xff09; 这个概念 在其他MQ产品里面也是有的&#xff0c;只不过在Rabbitmq中稍微特殊一点 什么叫私信队列呢&#xff1f; 就是当消息成为 dead message之后&#xff0c;可以重新发到另外一台交换机&#xff0c;这个交换机就是DLX。 注意这里的有翻…

基于OpenCV的人脸检测软件(含Python源码+UI界面+图文详解)

软件功能演示 摘要&#xff1a;人脸检测的目标是找出图像中所有的人脸对应的位置&#xff0c;算法的输出是人脸外接矩形在图像中的坐标&#xff0c;可能还包括姿态如倾斜角度等信息。本文详细介绍了其实现的技术原理&#xff0c;同时给出完整的Python实现代码&#xff0c;并且通…

GeoTools实战指南: 空间坐标系-地理信息科学的核心

GeoTools实战指南: 空间坐标系-地理信息科学的核心 引言 在我们的日常生活中,地图、GPS导航和地理位置服务已经变得司空见惯。但是,你有没有想过这些工具背后的工作原理呢?它们都依赖于一种称为"空间坐标系"的关键概念。本文将深入探讨空间坐标系的基础知识和其…

多线程专题(上)学习随手笔记

JMM&#xff1a;主内存物理内存线程共享&#xff0c;工作内存CPU缓存线程独占volatile&#xff1a;可见性、禁止指令重排&#xff0c;不可保证原子性&#xff1b;用于懒汉单例模式&#xff08;双重检测&#xff09;或状态标记Synchronized&#xff1a;保证代码块或方法同步化执…

Unity的URP下使用SRPBatcher

大家好&#xff0c;我是阿赵。这里继续来讲一下URP相关的东西。 这次主要说的是SRP Batcher的使用 一、在URP下实现SRP Batcher 1、设置 在我们创建的URPAsset文件的高级选项里面&#xff0c;有一个SRP Batcher的开关&#xff0c;默认就是勾上的。 2、修改shader 在把项目转…

小白白也能学会的 PyQt 教程 —— 自定义组件 Switch Button

文章目录 前言思路讲解代码部分 前言 最近在搞 Python 课程设计&#xff0c;想要搞一个好看的 UI&#xff0c;惊艳全班所有人。但打开 Qt Creator&#xff0c;Win7 风格的复古的按钮是在让我难以下手。 其次&#xff0c;我因为想要打造一个 Fluent UI 样式的设置页面&#xff…

详解c++STL—string组件

目录 一、string基本概念 1、本质 2、string和char * 区别&#xff1a; 3、特点&#xff1a; 二、string构造函数 1、构造函数原型 2、示例 三、string赋值操作 1、赋值的函数原型 2、示例 四、string字符串拼接 1、函数原型 2、示例 五、string查找和替换 1、功…

tomcat目录结构

tomcat服务器安装根目录下有很多子目录&#xff0c;这些目录的作用是&#xff1a; (1)bin&#xff1a;存放了tomcat服务器中的可执行的批处理文件(startup.bat shutdown.bat) (2)conf&#xff1a;存放了tomcat相关的配置文件(其中的server.xml是tomcat服务器核心配置文件) …

26. Pandas处理分析网站原始访问日志

Pandas处理分析网站原始访问日志 目标&#xff1a;真实项目的实战&#xff0c;探索Pandas的数据处理与分析 实例&#xff1a; 数据来源&#xff1a;我自己的wordpress博客蚂蚁学Python – 你有没有为写代码拼过命&#xff1f;那你知不知道 人生苦短&#xff0c;我用Python&am…

Python挑选出无Labelme标注文件的图片文件

Python挑选出无Labelme标注文件的图片文件 前言前提条件相关介绍实验环境Python挑选出无Labelme标注文件的图片文件代码实现输出结果 前言 本文是个人使用Python处理文件的电子笔记&#xff0c;由于水平有限&#xff0c;难免出现错漏&#xff0c;敬请批评改正。 (https://blog.…

【设计原则与思想:总结课】38 | 总结回顾面向对象、设计原则、编程规范、重构技巧等知识点

到今天为止&#xff0c;设计原则和思想已经全部讲完了&#xff0c;其中包括&#xff1a;面向对象、设计原则、规范与重构三个模块的内容。除此之外&#xff0c;我们还学习了贯穿整个专栏的代码质量评判标准。专栏的进度已经接近一半&#xff0c;马上就要进入设计模式内容的学习…

Python: 生成ubuntu apt镜像地址

文章目录 1. 目的2. 设计3. 实现4. 调用5. 参考 1. 目的 每次新配置 Ubuntu 系统&#xff0c;免不了配置 apt 源。尽管可以通过 GUI 界面进行选择&#xff0c;但自动化程度不够&#xff0c;不同桌面&#xff08;Unity/Gnome/KDE&#xff09;下的界面也不太一样&#xff1b; 使…

Java基础-sleep和wait的区别

本文介绍Java中sleep和wait方法的使用区别 文章目录 sleep()wait()sleep()和wait()对比区别相同点 sleep() 查看sleep方法&#xff0c;可见其是static native方法 public static native void sleep(long millis) throws InterruptedException;sleep()方法需要指定等待的时间。…

HTTP第14讲——HTTP传输大文件的方法

背景 HTTP 可以传输很多种类的数据&#xff0c;不仅是文本&#xff0c;也能传输图片、音频和视频。 早期互联网上传输的基本上都是只有几 K 大小的文本和小图片&#xff0c;现在的情况则大有不同。网页里包含的信息实在是太多了&#xff0c;随随便便一个主页 HTML 就有可能上百…

java常用集合

java集合又是一个新世界了&#xff0c;从前在我刚接触java的时候&#xff0c;一直在纠结 集合这东西到底有啥用&#xff0c;后来代码写的多了。才开始学习集合 集合也叫容器。顾名思意 就是存放对象的器皿。 主要是由两大接口派生而来 &#xff1a;一个是 Collecton接口&#…

LeetCode高频算法刷题记录2

文章目录 1. 最大子数组和【简单】1.1 题目描述1.2 解题思路1.3 代码实现 2. 合并两个有序链表【简单】2.1 题目描述2.2 解题思路2.3 代码实现 3. 两数之和【简单】3.1 题目描述3.2 解题思路3.3 代码实现 4. 二叉树的层序遍历【中等】4.1 题目描述4.2 解题思路4.3 代码实现 5. …