计算机课设——基于Java web的超市管理系统

smbms_java_web

基于Java web的超市管理系统,数据库课程设计

1.引言

是一个基于Java Web连接MySQL的小项目。

超市管理系统(smbms)作为每个计算机专业的大学生都是一个很好的练手项目,逻辑层次分明,基础功能包括用户的登录和注销,用户和供应商以及订单信息的增删查改的基础功能。可以帮助我们更好的加深理解三层架构的理念,本项目作为纯Java Web版,不涉及Spring和SpringBoot的知识,就是帮助我们从底层和从源代码开始理解,为以后的微服务和作铺垫。

2.项目框图

系统整体架构简略图如下:

image-20211209220942861

3.数据库准备工作

数据库以及数据表的架构设计如下:

image-20211209222332228

打开SQL yog,输入以下数据库创建语句。

CREATE DATABASE `smbms`;USE `smbms`;CREATE TABLE `smbms_address` (`id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',`contact` VARCHAR(15) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '联系人姓名',`addressDesc` VARCHAR(50) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '收货地址明细',`postCode` VARCHAR(15) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '邮编',`tel` VARCHAR(20) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '联系人电话',`createdBy` BIGINT(20) DEFAULT NULL COMMENT '创建者',`creationDate` DATETIME DEFAULT NULL COMMENT '创建时间',`modifyBy` BIGINT(20) DEFAULT NULL COMMENT '修改者',`modifyDate` DATETIME DEFAULT NULL COMMENT '修改时间',`userId` BIGINT(20) DEFAULT NULL COMMENT '用户ID',PRIMARY KEY (`id`)
) ENGINE=INNODB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;INSERT  INTO `smbms_address`(`id`,`contact`,`addressDesc`,`postCode`,`tel`,`createdBy`,`creationDate`,`modifyBy`,`modifyDate`,`userId`) VALUES (1,'王丽','北京市东城区东交民巷44号','100010','13678789999',1,'2016-04-13 00:00:00',NULL,NULL,1),(2,'张红丽','北京市海淀区丹棱街3号','100000','18567672312',1,'2016-04-13 00:00:00',NULL,NULL,1),(3,'任志强','北京市东城区美术馆后街23号','100021','13387906742',1,'2016-04-13 00:00:00',NULL,NULL,1),(4,'曹颖','北京市朝阳区朝阳门南大街14号','100053','13568902323',1,'2016-04-13 00:00:00',NULL,NULL,2),(5,'李慧','北京市西城区三里河路南三巷3号','100032','18032356666',1,'2016-04-13 00:00:00',NULL,NULL,3),(6,'王国强','北京市顺义区高丽营镇金马工业区18号','100061','13787882222',1,'2016-04-13 00:00:00',NULL,NULL,3);DROP TABLE IF EXISTS `smbms_bill`;CREATE TABLE `smbms_bill` (`id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',`billCode` VARCHAR(20) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '账单编码',`productName` VARCHAR(20) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '商品名称',`productDesc` VARCHAR(50) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '商品描述',`productUnit` VARCHAR(10) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '商品单位',`productCount` DECIMAL(20,2) DEFAULT NULL COMMENT '商品数量',`totalPrice` DECIMAL(20,2) DEFAULT NULL COMMENT '商品总额',`isPayment` INT(10) DEFAULT NULL COMMENT '是否支付(1:未支付 2:已支付)',`createdBy` BIGINT(20) DEFAULT NULL COMMENT '创建者(userId)',`creationDate` DATETIME DEFAULT NULL COMMENT '创建时间',`modifyBy` BIGINT(20) DEFAULT NULL COMMENT '更新者(userId)',`modifyDate` DATETIME DEFAULT NULL COMMENT '更新时间',`providerId` BIGINT(20) DEFAULT NULL COMMENT '供应商ID',PRIMARY KEY (`id`)
) ENGINE=INNODB AUTO_INCREMENT=19 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;INSERT  INTO `smbms_bill`(`id`,`billCode`,`productName`,`productDesc`,`productUnit`,`productCount`,`totalPrice`,`isPayment`,`createdBy`,`creationDate`,`modifyBy`,`modifyDate`,`providerId`) VALUES (2,'BILL2016_002','香皂、肥皂、药皂','日用品-皂类','块','1000.00','10000.00',2,1,'2016-03-23 04:20:40',NULL,NULL,13),(3,'BILL2016_003','大豆油','食品-食用油','斤','300.00','5890.00',2,1,'2014-12-14 13:02:03',NULL,NULL,6),(4,'BILL2016_004','橄榄油','食品-进口食用油','斤','200.00','9800.00',2,1,'2013-10-10 03:12:13',NULL,NULL,7),(5,'BILL2016_005','洗洁精','日用品-厨房清洁','瓶','500.00','7000.00',2,1,'2014-12-14 13:02:03',NULL,NULL,9),(6,'BILL2016_006','美国大杏仁','食品-坚果','袋','300.00','5000.00',2,1,'2016-04-14 06:08:09',NULL,NULL,4),(7,'BILL2016_007','沐浴液、精油','日用品-沐浴类','瓶','500.00','23000.00',1,1,'2016-07-22 10:10:22',NULL,NULL,14),(8,'BILL2016_008','不锈钢盘碗','日用品-厨房用具','个','600.00','6000.00',2,1,'2016-04-14 05:12:13',NULL,NULL,14),(9,'BILL2016_009','塑料杯','日用品-杯子','个','350.00','1750.00',2,1,'2016-02-04 11:40:20',NULL,NULL,14),(10,'BILL2016_010','豆瓣酱','食品-调料','瓶','200.00','2000.00',2,1,'2013-10-29 05:07:03',NULL,NULL,8),(11,'BILL2016_011','海之蓝','饮料-国酒','瓶','50.00','10000.00',1,1,'2016-04-14 16:16:00',NULL,NULL,1),(12,'BILL2016_012','芝华士','饮料-洋酒','瓶','20.00','6000.00',1,1,'2016-09-09 17:00:00',NULL,NULL,1),(13,'BILL2016_013','长城红葡萄酒','饮料-红酒','瓶','60.00','800.00',2,1,'2016-11-14 15:23:00',NULL,NULL,1),(14,'BILL2016_014','泰国香米','食品-大米','斤','400.00','5000.00',2,1,'2016-10-09 15:20:00',NULL,NULL,3),(15,'BILL2016_015','东北大米','食品-大米','斤','600.00','4000.00',2,1,'2016-11-14 14:00:00',NULL,NULL,3),(16,'BILL2016_016','可口可乐','饮料','瓶','2000.00','6000.00',2,1,'2012-03-27 13:03:01',NULL,NULL,2),(17,'BILL2016_017','脉动','饮料','瓶','1500.00','4500.00',2,1,'2016-05-10 12:00:00',NULL,NULL,2),(18,'BILL2016_018','哇哈哈','饮料','瓶','2000.00','4000.00',2,1,'2015-11-24 15:12:03',NULL,NULL,2);DROP TABLE IF EXISTS `smbms_provider`;CREATE TABLE `smbms_provider` (`id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',`proCode` VARCHAR(20) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '供应商编码',`proName` VARCHAR(20) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '供应商名称',`proDesc` VARCHAR(50) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '供应商详细描述',`proContact` VARCHAR(20) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '供应商联系人',`proPhone` VARCHAR(20) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '联系电话',`proAddress` VARCHAR(50) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '地址',`proFax` VARCHAR(20) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '传真',`createdBy` BIGINT(20) DEFAULT NULL COMMENT '创建者(userId)',`creationDate` DATETIME DEFAULT NULL COMMENT '创建时间',`modifyDate` DATETIME DEFAULT NULL COMMENT '更新时间',`modifyBy` BIGINT(20) DEFAULT NULL COMMENT '更新者(userId)',PRIMARY KEY (`id`)
) ENGINE=INNODB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;INSERT  INTO `smbms_provider`(`id`,`proCode`,`proName`,`proDesc`,`proContact`,`proPhone`,`proAddress`,`proFax`,`createdBy`,`creationDate`,`modifyDate`,`modifyBy`) VALUES (1,'BJ_GYS001','北京三木堂商贸有限公司','长期合作伙伴,主营产品:茅台、五粮液、郎酒、酒鬼酒、泸州老窖、赖茅酒、法国红酒等','张国强','13566667777','北京市丰台区育芳园北路','010-58858787',1,'2013-03-21 16:52:07',NULL,NULL),(2,'HB_GYS001','石家庄帅益食品贸易有限公司','长期合作伙伴,主营产品:饮料、水饮料、植物蛋白饮料、休闲食品、果汁饮料、功能饮料等','王军','13309094212','河北省石家庄新华区','0311-67738876',1,'2016-04-13 04:20:40',NULL,NULL),(3,'GZ_GYS001','深圳市泰香米业有限公司','初次合作伙伴,主营产品:良记金轮米,龙轮香米等','郑程瀚','13402013312','广东省深圳市福田区深南大道6006华丰大厦','0755-67776212',1,'2014-03-21 16:56:07',NULL,NULL),(4,'GZ_GYS002','深圳市喜来客商贸有限公司','长期合作伙伴,主营产品:坚果炒货.果脯蜜饯.天然花茶.营养豆豆.特色美食.进口食品.海味零食.肉脯肉','林妮','18599897645','广东省深圳市福龙工业区B2栋3楼西','0755-67772341',1,'2013-03-22 16:52:07',NULL,NULL),(5,'JS_GYS001','兴化佳美调味品厂','长期合作伙伴,主营产品:天然香辛料、鸡精、复合调味料','徐国洋','13754444221','江苏省兴化市林湖工业区','0523-21299098',1,'2015-11-22 16:52:07',NULL,NULL),(6,'BJ_GYS002','北京纳福尔食用油有限公司','长期合作伙伴,主营产品:山茶油、大豆油、花生油、橄榄油等','马莺','13422235678','北京市朝阳区珠江帝景1号楼','010-588634233',1,'2012-03-21 17:52:07',NULL,NULL),(7,'BJ_GYS003','北京国粮食用油有限公司','初次合作伙伴,主营产品:花生油、大豆油、小磨油等','王驰','13344441135','北京大兴青云店开发区','010-588134111',1,'2016-04-13 00:00:00',NULL,NULL),(8,'ZJ_GYS001','慈溪市广和绿色食品厂','长期合作伙伴,主营产品:豆瓣酱、黄豆酱、甜面酱,辣椒,大蒜等农产品','薛圣丹','18099953223','浙江省宁波市慈溪周巷小安村','0574-34449090',1,'2013-11-21 06:02:07',NULL,NULL),(9,'GX_GYS001','优百商贸有限公司','长期合作伙伴,主营产品:日化产品','李立国','13323566543','广西南宁市秀厢大道42-1号','0771-98861134',1,'2013-03-21 19:52:07',NULL,NULL),(10,'JS_GYS002','南京火头军信息技术有限公司','长期合作伙伴,主营产品:不锈钢厨具等','陈女士','13098992113','江苏省南京市浦口区浦口大道1号新城总部大厦A座903室','025-86223345',1,'2013-03-25 16:52:07',NULL,NULL),(11,'GZ_GYS003','广州市白云区美星五金制品厂','长期合作伙伴,主营产品:海绵床垫、坐垫、靠垫、海绵枕头、头枕等','梁天','13562276775','广州市白云区钟落潭镇福龙路20号','020-85542231',1,'2016-12-21 06:12:17',NULL,NULL),(12,'BJ_GYS004','北京隆盛日化科技','长期合作伙伴,主营产品:日化环保清洗剂,家居洗涤专卖、洗涤用品网、墙体除霉剂、墙面霉菌清除剂等','孙欣','13689865678','北京市大兴区旧宫','010-35576786',1,'2014-11-21 12:51:11',NULL,NULL),(13,'SD_GYS001','山东豪克华光联合发展有限公司','长期合作伙伴,主营产品:洗衣皂、洗衣粉、洗衣液、洗洁精、消杀类、香皂等','吴洪转','13245468787','山东济阳济北工业区仁和街21号','0531-53362445',1,'2015-01-28 10:52:07',NULL,NULL),(14,'JS_GYS003','无锡喜源坤商行','长期合作伙伴,主营产品:日化品批销','周一清','18567674532','江苏无锡盛岸西路','0510-32274422',1,'2016-04-23 11:11:11',NULL,NULL),(15,'ZJ_GYS002','乐摆日用品厂','长期合作伙伴,主营产品:各种中、高档塑料杯,塑料乐扣水杯(密封杯)、保鲜杯(保鲜盒)、广告杯、礼品杯','王世杰','13212331567','浙江省金华市义乌市义东路','0579-34452321',1,'2016-08-22 10:01:30',NULL,NULL);DROP TABLE IF EXISTS `smbms_role`;CREATE TABLE `smbms_role` (`id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',`roleCode` VARCHAR(15) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '角色编码',`roleName` VARCHAR(15) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '角色名称',`createdBy` BIGINT(20) DEFAULT NULL COMMENT '创建者',`creationDate` DATETIME DEFAULT NULL COMMENT '创建时间',`modifyBy` BIGINT(20) DEFAULT NULL COMMENT '修改者',`modifyDate` DATETIME DEFAULT NULL COMMENT '修改时间',PRIMARY KEY (`id`)
) ENGINE=INNODB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;INSERT  INTO `smbms_role`(`id`,`roleCode`,`roleName`,`createdBy`,`creationDate`,`modifyBy`,`modifyDate`) VALUES (1,'SMBMS_ADMIN','系统管理员',1,'2016-04-13 00:00:00',NULL,NULL),(2,'SMBMS_MANAGER','经理',1,'2016-04-13 00:00:00',NULL,NULL),(3,'SMBMS_EMPLOYEE','普通员工',1,'2016-04-13 00:00:00',NULL,NULL);DROP TABLE IF EXISTS `smbms_user`;CREATE TABLE `smbms_user` (`id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '主键ID',`userCode` VARCHAR(15) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '用户编码',`userName` VARCHAR(15) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '用户名称',`userPassword` VARCHAR(15) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '用户密码',`gender` INT(10) DEFAULT NULL COMMENT '性别(1:女、 2:男)',`birthday` DATE DEFAULT NULL COMMENT '出生日期',`phone` VARCHAR(15) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '手机',`address` VARCHAR(30) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '地址',`userRole` BIGINT(20) DEFAULT NULL COMMENT '用户角色(取自角色表-角色id)',`createdBy` BIGINT(20) DEFAULT NULL COMMENT '创建者(userId)',`creationDate` DATETIME DEFAULT NULL COMMENT '创建时间',`modifyBy` BIGINT(20) DEFAULT NULL COMMENT '更新者(userId)',`modifyDate` DATETIME DEFAULT NULL COMMENT '更新时间',PRIMARY KEY (`id`)
) ENGINE=INNODB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;INSERT  INTO `smbms_user`(`id`,`userCode`,`userName`,`userPassword`,`gender`,`birthday`,`phone`,`address`,`userRole`,`createdBy`,`creationDate`,`modifyBy`,`modifyDate`) VALUES (1,'admin','系统管理员','1234567',1,'1983-10-10','13688889999','北京市海淀区成府路207号',1,1,'2013-03-21 16:52:07',NULL,NULL),(2,'liming','李明','0000000',2,'1983-12-10','13688884457','北京市东城区前门东大街9号',2,1,'2014-12-31 19:52:09',NULL,NULL),(5,'hanlubiao','韩路彪','0000000',2,'1984-06-05','18567542321','北京市朝阳区北辰中心12号',2,1,'2014-12-31 19:52:09',NULL,NULL),(6,'zhanghua','张华','0000000',1,'1983-06-15','13544561111','北京市海淀区学院路61号',3,1,'2013-02-11 10:51:17',NULL,NULL),(7,'wangyang','王洋','0000000',2,'1982-12-31','13444561124','北京市海淀区西二旗辉煌国际16层',3,1,'2014-06-11 19:09:07',NULL,NULL),(8,'zhaoyan','赵燕','0000000',1,'1986-03-07','18098764545','北京市海淀区回龙观小区10号楼',3,1,'2016-04-21 13:54:07',NULL,NULL),(10,'sunlei','孙磊','0000000',2,'1981-01-04','13387676765','北京市朝阳区管庄新月小区12楼',3,1,'2015-05-06 10:52:07',NULL,NULL),(11,'sunxing','孙兴','0000000',2,'1978-03-12','13367890900','北京市朝阳区建国门南大街10号',3,1,'2016-11-09 16:51:17',NULL,NULL),(12,'zhangchen','张晨','0000000',1,'1986-03-28','18098765434','朝阳区管庄路口北柏林爱乐三期13号楼',3,1,'2016-08-09 05:52:37',1,'2016-04-14 14:15:36'),(13,'dengchao','邓超','0000000',2,'1981-11-04','13689674534','北京市海淀区北航家属院10号楼',3,1,'2016-07-11 08:02:47',NULL,NULL),(14,'yangguo','杨过','0000000',2,'1980-01-01','13388886623','北京市朝阳区北苑家园茉莉园20号楼',3,1,'2015-02-01 03:52:07',NULL,NULL),(15,'zhaomin','赵敏','0000000',1,'1987-12-04','18099897657','北京市昌平区天通苑3区12号楼',2,1,'2015-09-12 12:02:12',NULL,NULL);

4.创建Maven Web项目

通过webapp模板创建,不会的参考java web相关笔记。

搭建项目,创建相关包、目录结构,然后配置Tomcat服务器。

设置好pom.xml的依赖环境:

<dependencies><!--    servlet--><dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>4.0.0</version><scope>provided</scope></dependency><!--    jsp--><dependency><groupId>javax.servlet.jsp</groupId><artifactId>jsp-api</artifactId><version>2.2</version></dependency><!--      mysql--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>5.1.47</version></dependency><!--    JSTL表达式--><dependency><groupId>javax.servlet</groupId><artifactId>jstl</artifactId><version>1.2</version></dependency><!--      standard--><dependency><groupId>taglibs</groupId><artifactId>standard</artifactId><version>1.1.2</version></dependency>
</dependencies>

创建项目包结构:

image-20211210135413620

dao层用于操作数据库的数据,将数据库的连接,关闭以及增删改查等方法封装起来。

pojo是根据数据库中的字段信息编写的实体类。

service业务层调用DAO层的方法。

servlet层实现前后端的交互。

测试idea连接数据库:参考MySQL学习笔记(十)。

DAO模式:

DAO (DataAccessobjects 数据存取对象)是指位于业务逻辑和持久化数据之间实现对持久化数据的访问。通俗来讲,就是将数据库操作都封装起来。

一篇简短的介绍

关于DAO的详细知识参考韩顺平jdbc教程

一个典型的DAO 模式主要由以下几部分组成。

  • 1、DAO接口: 把对数据库的所有操作定义成抽象方法,可以提供多种实现。
  • 2、DAO 实现类: 针对不同数据库给出DAO接口定义方法的具体实现。
  • 3、实体类:用于存放与传输对象数据。
  • 4、数据库连接和关闭工具类: 避免了数据库连接和关闭代码的重复使用,方便修改。

5.建立实体类

就是ORM映射思想 将数据库表和实体类一 一对应。(表–>类映射)

建立四个实体类。

pojo之下新建User.java

import java.util.Date;public class User {private Integer id;private String userCode;    //用户编码private String userName;private String userPassword;private Integer gender;private Date birthday;private String phone;private String address;private Integer userRole;private Integer createdBy;  //创建者private Date creationDate;private Integer modifyBy;   //更新者private Date modifyDate;    //更新时间private Integer age;    //年龄private String userRoleName;    //用户角色名称public Integer getAge() {Date date = new Date();Integer age = date.getYear()-birthday.getYear();return age;}public void setAge(Integer age) {this.age = age;}public String getUserRoleName() {return userRoleName;}public void setUserRoleName(String userRoleName) {this.userRoleName = userRoleName;}public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getUserCode() {return userCode;}public void setUserCode(String userCode) {this.userCode = userCode;}public String getUserName() {return userName;}public void setUserName(String userName) {this.userName = userName;}public String getUserPassword() {return userPassword;}public void setUserPassword(String userPassword) {this.userPassword = userPassword;}public Integer getGender() {return gender;}public void setGender(Integer gender) {this.gender = gender;}public Date getBirthday() {return birthday;}public void setBirthday(Date birthday) {this.birthday = birthday;}public String getPhone() {return phone;}public void setPhone(String phone) {this.phone = phone;}public String getAddress() {return address;}public void setAddress(String address) {this.address = address;}public Integer getUserRole() {return userRole;}public void setUserRole(Integer userRole) {this.userRole = userRole;}public Integer getCreatedBy() {return createdBy;}public void setCreatedBy(Integer createdBy) {this.createdBy = createdBy;}public Date getcreationDate() {return creationDate;}public void setcreationDate(Date creationDate) {this.creationDate = creationDate;}public Integer getModifyBy() {return modifyBy;}public void setModifyBy(Integer modifyBy) {this.modifyBy = modifyBy;}public Date getModifyDate() {return modifyDate;}public void setModifyDate(Date modifyDate) {this.modifyDate = modifyDate;}
}

pojo之下新建Role.java

import java.util.Date;
public class Role {private Integer id;   //idprivate String roleCode; //角色编码private String roleName; //角色名称private Integer createdBy; //创建者private Date creationDate; //创建时间private Integer modifyBy; //更新者private Date modifyDate;//更新时间public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getRoleCode() {return roleCode;}public void setRoleCode(String roleCode) {this.roleCode = roleCode;}public String getRoleName() {return roleName;}public void setRoleName(String roleName) {this.roleName = roleName;}public Integer getCreatedBy() {return createdBy;}public void setCreatedBy(Integer createdBy) {this.createdBy = createdBy;}public Date getCreationDate() {return creationDate;}public void setCreationDate(Date creationDate) {this.creationDate = creationDate;}public Integer getModifyBy() {return modifyBy;}public void setModifyBy(Integer modifyBy) {this.modifyBy = modifyBy;}public Date getModifyDate() {return modifyDate;}public void setModifyDate(Date modifyDate) {this.modifyDate = modifyDate;}
}

pojo之下新建Provider.java

import java.util.Date;
public class Provider {private Integer id;   //idprivate String proCode; //供应商编码private String proName; //供应商名称private String proDesc; //供应商描述private String proContact; //供应商联系人private String proPhone; //供应商电话private String proAddress; //供应商地址private String proFax; //供应商传真private Integer createdBy; //创建者private Date creationDate; //创建时间private Integer modifyBy; //更新者private Date modifyDate;//更新时间public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getProCode() {return proCode;}public void setProCode(String proCode) {this.proCode = proCode;}public String getProName() {return proName;}public void setProName(String proName) {this.proName = proName;}public String getProDesc() {return proDesc;}public void setProDesc(String proDesc) {this.proDesc = proDesc;}public String getProContact() {return proContact;}public void setProContact(String proContact) {this.proContact = proContact;}public String getProPhone() {return proPhone;}public void setProPhone(String proPhone) {this.proPhone = proPhone;}public String getProAddress() {return proAddress;}public void setProAddress(String proAddress) {this.proAddress = proAddress;}public String getProFax() {return proFax;}public void setProFax(String proFax) {this.proFax = proFax;}public Integer getCreatedBy() {return createdBy;}public void setCreatedBy(Integer createdBy) {this.createdBy = createdBy;}public Date getCreationDate() {return creationDate;}public void setCreationDate(Date creationDate) {this.creationDate = creationDate;}public Integer getModifyBy() {return modifyBy;}public void setModifyBy(Integer modifyBy) {this.modifyBy = modifyBy;}public Date getModifyDate() {return modifyDate;}public void setModifyDate(Date modifyDate) {this.modifyDate = modifyDate;}
}

pojo之下新建Bill.java

import java.math.BigDecimal;
import java.util.Date;
public class Bill {private Integer id;   //idprivate String billCode; //账单编码private String productName; //商品名称private String productDesc; //商品描述private String productUnit; //商品单位private BigDecimal productCount; //商品数量private BigDecimal totalPrice; //总金额private Integer isPayment; //是否支付private Integer providerId; //供应商IDprivate Integer createdBy; //创建者private Date creationDate; //创建时间private Integer modifyBy; //更新者private Date modifyDate;//更新时间private String providerName;//供应商名称public String getProviderName() {return providerName;}public void setProviderName(String providerName) {this.providerName = providerName;}public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getBillCode() {return billCode;}public void setBillCode(String billCode) {this.billCode = billCode;}public String getProductName() {return productName;}public void setProductName(String productName) {this.productName = productName;}public String getProductDesc() {return productDesc;}public void setProductDesc(String productDesc) {this.productDesc = productDesc;}public String getProductUnit() {return productUnit;}public void setProductUnit(String productUnit) {this.productUnit = productUnit;}public BigDecimal getProductCount() {return productCount;}public void setProductCount(BigDecimal productCount) {this.productCount = productCount;}public BigDecimal getTotalPrice() {return totalPrice;}public void setTotalPrice(BigDecimal totalPrice) {this.totalPrice = totalPrice;}public Integer getIsPayment() {return isPayment;}public void setIsPayment(Integer isPayment) {this.isPayment = isPayment;}public Integer getProviderId() {return providerId;}public void setProviderId(Integer providerId) {this.providerId = providerId;}public Integer getCreatedBy() {return createdBy;}public void setCreatedBy(Integer createdBy) {this.createdBy = createdBy;}public Date getCreationDate() {return creationDate;}public void setCreationDate(Date creationDate) {this.creationDate = creationDate;}public Integer getModifyBy() {return modifyBy;}public void setModifyBy(Integer modifyBy) {this.modifyBy = modifyBy;}public Date getModifyDate() {return modifyDate;}public void setModifyDate(Date modifyDate) {this.modifyDate = modifyDate;}
}

6.编写基础公共类

6.1 数据库配置文件

resources之下新建db.properties

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/smbms?useSSL=false&useUnicode=true&characterEncoding=utf8
username=root
password=xxxxx        // 数据库名和密码自己改一下

6.2 在Dao层编写操作数据库的公共类

dao 下新建BaseDao.java

import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;public class BaseDao {private static String driver;private static String url;private static String username;private static String password;//静态代码块 类加载的时候初始化static {Properties properties = new Properties();//通过类加载器读取对应的资源InputStream is = BaseDao.class.getClassLoader().getResourceAsStream("db.properties");//  properties读取文件内容try {properties.load(is);} catch (IOException e) {e.printStackTrace();}driver = properties.getProperty("driver");url = properties.getProperty("url");username = properties.getProperty("username");password = properties.getProperty("password");}//获取数据库的连接public static Connection getConnection(){Connection conn = null;try {Class.forName(driver);conn = DriverManager.getConnection(url, username, password);} catch (Exception e) {e.printStackTrace();}return conn;}//编写查询公共方法public static ResultSet execute(Connection conn,String sql,PreparedStatement preparedStatement,Object[] params,ResultSet resultSet) throws SQLException {//预编译的sql在后面直接执行即可preparedStatement = conn.prepareStatement(sql);for (int i = 0; i < params.length; i++) {//setObject 占位符从1开始 而数字从0开始preparedStatement.setObject(i+1,params[i]);}resultSet = preparedStatement.executeQuery();return resultSet;}//编写增删改查公共方法public static int execute(Connection conn,String sql,PreparedStatement preparedStatement,Object[] params) throws SQLException {//预编译的sql在后面直接执行即可int updateRow;preparedStatement = conn.prepareStatement(sql);for (int i = 0; i < params.length; i++) {//setObject 占位符从1开始 而数字从0开始preparedStatement.setObject(i+1,params[i]);}updateRow = preparedStatement.executeUpdate();return updateRow;}//释放资源public static boolean closeResource(Connection conn,PreparedStatement preparedStatement,ResultSet resultSet){boolean flag = true;if(conn!=null){try {conn.close();//GC回收conn = null;} catch (SQLException e) {e.printStackTrace();flag = false;}}if(preparedStatement!=null){try {preparedStatement.close();//GC回收preparedStatement = null;} catch (SQLException e) {e.printStackTrace();flag = false;}}if(resultSet!=null){try {resultSet.close();//GC回收resultSet = null;} catch (SQLException e) {e.printStackTrace();flag = false;}}return flag;}
}

7.编写过滤器处理中文乱码

filter下新建CharacterENcodingFilter.java

import javax.servlet.*;
import java.io.IOException;public class CharacterEncodingFilter implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {}@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {servletRequest.setCharacterEncoding("utf-8");servletResponse.setCharacterEncoding("utf-8");filterChain.doFilter(servletRequest,servletResponse);}@Overridepublic void destroy() {}
}

写完过滤器记得在WEB.xml中进行注册:

<!--字符过滤器-->
<filter><filter-name>CharacterEncodingFilter</filter-name><filter-class>top.grantdrew.filter.CharacterEncodingFilter</filter-class>
</filter>
<filter-mapping><filter-name>CharacterEncodingFilter</filter-name><url-pattern>/*</url-pattern>
</filter-mapping>

8.导入前端资源文件

记得是在webapp下面:

image-20211210161042640

9.编写登录模块

登录流程图解:

image-20211210161456464

编写login.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"pageEncoding="UTF-8"%>
<html>
<head lang="en"><meta charset="UTF-8"><title>系统登录 - 超市订单管理系统</title><link type="text/css" rel="stylesheet" href="${pageContext.request.contextPath }/css/style.css" /><script type="text/javascript">/* if(top.location!=self.location){top.location=self.location;} */</script>
</head>
<body class="login_bg">
<section class="loginBox"><header class="loginHeader"><h1>超市订单管理系统</h1></header><section class="loginCont"><form class="loginForm" action="${pageContext.request.contextPath }/login.do"  name="actionForm" id="actionForm"  method="post" ><div class="info">${error}</div><div class="inputbox"><label for="userCode">用户名:</label><input type="text" class="input-text" id="userCode" name="userCode" placeholder="请输入用户名" required/></div><div class="inputbox"><label for="userPassword">密码:</label><input type="password" id="userPassword" name="userPassword" placeholder="请输入密码" required/></div><div class="subBtn"><input type="submit" value="登录"/><input type="reset" value="重置"/></div></form></section>
</section>
</body>
</html>

web.xml中将login.jsp设置为欢迎页(首页):

<welcome-file-list><welcome-file>login.jsp</welcome-file>
</welcome-file-list>

9.1 编写dao层用户登录的接口UserDao

这一步的主要功能就是从首页获取用户输入的名称和密码,与数据库中的数据进行对比。

dao包下新建user包,在user包下新建UserDao接口:

import top.grantdrew.pojo.User;import java.sql.Connection;public interface UserDao {public User getLoginUser(Connection con,String userCode);
}

9.2 编写接口UserDao的实现类

UserDaoImpl.java

import com.csnz.dao.BaseDao;
import com.csnz.pojo.User;import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
//登录 判断 的实现类
public class UserDaoImpl implements UserDao {@Override//得到要登录的用户信息public User getLoginInfo(Connection conn, String userCode) throws SQLException {PreparedStatement preparedStatement = null;ResultSet rs = null;User user = null;//如果连数据库都没连接就无需判断了if(conn!=null){//编写sql语句String sql = "select * from smbms_user where userCode = ?";//存放参数Object[] params = {userCode};//使用预处理对象调用  操作数据库的公共类 的执行 sql查询语句rs = BaseDao.executeQuery(conn, sql, preparedStatement, params,rs);//遍历结果集  封装到一个用户中if(rs.next()){user = new User();user.setId(rs.getInt("id"));user.setUserCode(rs.getString("userCode"));user.setUserName(rs.getString("userName"));user.setUserPassword(rs.getString("userPassword"));user.setGender(rs.getInt("gender"));user.setBirthday(rs.getDate("birthday"));user.setPhone(rs.getString("phone"));user.setAddress(rs.getString("address"));user.setUserRole(rs.getInt("userRole"));user.setCreatedBy(rs.getInt("createdBy"));user.setCreateDate(rs.getTimestamp("creationDate"));user.setModifyBy(rs.getInt("modifyBy"));user.setModifyDate(rs.getTimestamp("modifyDate"));}//调用  操作数据库的公共类 的执行 释放资源BaseDao.closeResource(null,preparedStatement,rs); // 数据库连接暂时不用关闭}//返回一个用户return user;}
}

9.3 编写业务层接口与实现类

service包下新建user包,然后在下面新建UserService接口:

import com.csnz.pojo.User;
public interface UserService {//用户登录public abstract User login(String userCode,String passWord);
}

service包下的user包下新建UserServlce接口的实现类:

import org.junit.Test;
import top.grantdrew.dao.BaseDao;
import top.grantdrew.dao.user.UserDao;
import top.grantdrew.dao.user.UserDaoImpl;
import top.grantdrew.pojo.User;import java.sql.Connection;
import java.sql.SQLException;public class UserServiceImpl implements UserService{private UserDao userDao;public UserServiceImpl(){userDao = new UserDaoImpl();}@Overridepublic User login(String userCode, String password) {Connection con = null;User user = null;con = BaseDao.getConnection();user = userDao.getLoginUser(con,userCode);try {BaseDao.release(con,null,null);} catch (SQLException throwables) {throwables.printStackTrace();}return  user;}@Test public void test(){ // 这里写了一个临时的测试方法,测试完后删除UserServiceImpl userService = new UserServiceImpl();User user = userService.login("admin","1243534");System.out.println(user.getUserName());System.out.println(user.getUserPassword());}
}

10.编写用户登录的Servlet

util包之下新建Constant类,存放用户登录状态字符串。

package top.grantdrew.util;public class Constant {public final static String USER_SESSION = "userSession";
}

servlet包之下新建user包,建立LoginServlet.java

import top.grantdrew.pojo.User;
import top.grantdrew.service.user.UserService;
import top.grantdrew.service.user.UserServiceImpl;
import top.grantdrew.util.Constant;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 {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// 获取前端表单的参数String userCode = req.getParameter("userCode");String userPassword = req.getParameter("userPassword");UserService userService = new UserServiceImpl();User user = userService.login(userCode,userPassword);if (user != null){req.getSession().setAttribute(Constant.USER_SESSION,user);resp.sendRedirect("jsp/frame.jsp"); // 登录成功跳转主页}else{req.setAttribute("error","用户名或密码不正确!"); // 在前端jsp页面输出相应信息req.getRequestDispatcher("login.jsp").forward(req,resp);}}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {doGet(req, resp);}
}

别忘了在web.xml中注册servlet:

<servlet><servlet-name>LoginServlet</servlet-name><servlet-class>top.grantdrew.servlet.user.LoginServlet</servlet-class>
</servlet>
<servlet-mapping><servlet-name>LoginServlet</servlet-name><url-pattern>/login.do</url-pattern>
</servlet-mapping>

BUG修复:

tomcat上运行servlet使用jdbc异常java.lang.ClassNotFoundException: com.mysql.jdbc.Driver。

解决方案:

在tomcat的lib目录下添加一个mysql对应版本的mysql-connector-java-5.1.47jar包就行。

BUG修复:

image-20211210214810567

解决方案:

在tomcat的lib目录下添加报错的jar包(jstl包)就行。(去maven仓库下载)

11.编写用户注销登录的Servlet

user包,建立LogoutServlet.java

import top.grantdrew.util.Constant;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 LogoutServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {req.getSession().removeAttribute(Constant.USER_SESSION);resp.sendRedirect(req.getContextPath() + "/login.jsp");}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {doGet(req, resp);}
}

别忘了注册一下注销的servlet:

<servlet><servlet-name>LogoutServlet</servlet-name><servlet-class>top.grantdrew.servlet.user.LogoutServlet</servlet-class>
</servlet>
<servlet-mapping><servlet-name>LogoutServlet</servlet-name><url-pattern>/jsp/logout.do</url-pattern>
</servlet-mapping>

11.用户登录拦截优化

使用过滤器来拦截未登录用户的非法访问。

新建SysFilter.java

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;public class SysFilter implements Filter {@Overridepublic void init(FilterConfig filterConfig) throws ServletException {}@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {HttpServletRequest req = (HttpServletRequest) servletRequest;HttpServletResponse resp = (HttpServletResponse) servletResponse;User user = (User) req.getSession().getAttribute(Constant.USER_SESSION);if (user == null){resp.sendRedirect(req.getContextPath() + "/error.jsp");}else{filterChain.doFilter(req,resp);}}@Overridepublic void destroy() {}
}

注册过滤器:

<filter><filter-name>SysFilter</filter-name><filter-class>top.grantdrew.filter.SysFilter</filter-class>
</filter>
<filter-mapping><filter-name>SysFilter</filter-name><url-pattern>/jsp/*</url-pattern>
</filter-mapping>

配置之后 当我们注销登录后 试图访问用户信息的界面 就会转向到 我们自定义——"找不到界面的 "页面。

12.修改密码模块

BUG修复:

浏览器显示jsp页面引入js的部分出现中文乱码的情况,尝试在引入js的标签中设置编码为utf-8没有用。

在浏览器通过F12查看上述js文件发现乱码。

解决方案:

记事本打开引起乱码的js文件,右键另存为ANSI格式覆盖。

引入js的标签中不需要设置编码为utf-8了。

改完格式之后最好清空项目的target目录并使用maven清空一下编译文件,然后重启tomcat,最后再建议清空一下浏览器缓存


建议的项目开发流程:自底向上,逐层调用。

image-20211211152222395

修改密码并验证两次输入的密码是否一致等工作,交给前端js来处理,也可以用后端servlet处理。

dao包下的user包下的UserDao接口中完善修改密码等方法,在它的实现类UserDaoImpl中实现方法。

 @Overridepublic int updatePwd(Connection con, int id, String password) {PreparedStatement preparedStatement = null;int rs = 0;if (con != null){String sql = "update smbms_user set userPassword = ? where id = ?";Object[] params = {password,id};try {rs = BaseDao.execute(con,sql,preparedStatement,params);} catch (SQLException throwables) {throwables.printStackTrace();}try {BaseDao.release(null,preparedStatement,null);} catch (SQLException throwables) {throwables.printStackTrace();}}return rs;}

然后在service包下的user包下实现相应方法:

@Override
public boolean updatePwd(int id, String password) {Connection con = BaseDao.getConnection();boolean flag = false;if (con != null){if (userDao.updatePwd(con,id,password) > 0){flag = true;}}return flag;
}

然后在servlet包下的user包下实现UserServlet

import top.grantdrew.pojo.User;
import top.grantdrew.service.user.UserService;
import top.grantdrew.service.user.UserServiceImpl;
import top.grantdrew.util.Constant;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 {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {doPost(req,resp);}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {String method = req.getParameter("method");  // 这个参数封装在前端页面if (method != null && method.equals("savepwd")){this.updatePwd(req,resp); // 后面对于用户的操作还有很多,这样提取出方法实现了servlet复用}}public void updatePwd(HttpServletRequest req,HttpServletResponse resp){Object o = req.getSession().getAttribute(Constant.USER_SESSION);String password = req.getParameter("newpassword");Boolean flag = false;if (o != null && password != null && password.length() != 0){UserService userService = new UserServiceImpl();flag = userService.updatePwd(((User)o).getId(),password);if (flag){req.getSession().setAttribute("message","修改密码成功,请使用新密码登录!");req.getSession().removeAttribute(Constant.USER_SESSION);}else{req.getSession().setAttribute("message","修改密码失败,请重新修改!");}}else{req.getSession().setAttribute("message","新密码不符合要求,请重新输入!");}try {req.getRequestDispatcher(req.getContextPath() + "/login.jsp").forward(req,resp);} catch (ServletException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}}
}

注册一下servl:

<servlet><servlet-name>UserServlet</servlet-name><servlet-class>top.grantdrew.servlet.user.UserServlet</servlet-class>
</servlet>
<servlet-mapping><servlet-name>UserServlet</servlet-name><url-pattern>/jsp/user.do</url-pattern>
</servlet-mapping>

13.使用Ajax优化密码修改

导阿里巴巴的fastjson依赖:

<!--      阿里巴巴的fastjson:用于转换json格式-->
<dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.61</version>
</dependency>

BUG修复:

导入上述依赖之后项目build失败,找不到fastjson的相关类。

推测原因:idea 2020版本与maven构建的build不相容。

解决方案:

image-20211211210354240

将idea的构建和运行托管到maven下面。勾选后,重新编译就能正常运行。

修改上面的UserServlet

import com.alibaba.fastjson.JSONArray;
import top.grantdrew.pojo.User;
import top.grantdrew.service.user.UserService;
import top.grantdrew.service.user.UserServiceImpl;
import top.grantdrew.util.Constant;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.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;public class UserServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {doPost(req,resp);}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {String method = req.getParameter("method");System.out.println("method:" + method);if (method != null && method.equals("savepwd")){this.updatePwd(req,resp);}else if (method != null && method.equals("pwdmodify")){this.pwdModify(req,resp);}}// 修改密码public void updatePwd(HttpServletRequest req,HttpServletResponse resp){Object o = req.getSession().getAttribute(Constant.USER_SESSION);String password = req.getParameter("newpassword");Boolean flag = false;if (o != null && password != null && password.length() != 0){UserService userService = new UserServiceImpl();flag = userService.updatePwd(((User)o).getId(),password);if (flag){req.getSession().setAttribute("message","修改密码成功,请使用新密码登录!");req.getSession().removeAttribute(Constant.USER_SESSION);}else{req.getSession().setAttribute("message","修改密码失败,请重新修改!");}}else{req.getSession().setAttribute("message","新密码不符合要求,请重新输入!");}try {req.getRequestDispatcher("pwdmodify.jsp").forward(req,resp);} catch (ServletException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}}// 验证旧密码,与ajax对应public void pwdModify(HttpServletRequest req,HttpServletResponse resp){Object o = req.getSession().getAttribute(Constant.USER_SESSION);String oldpqssword = req.getParameter("oldpassword");Map<String,String> resultMap = new HashMap<>();if (o == null){resultMap.put("result","sessionerror");}else if (!(oldpqssword != null && oldpqssword.length() != 0)){resultMap.put("result","error");} else {String password = ((User)o).getUserPassword();System.out.println("oldpassword: " + oldpqssword);System.out.println("password " + password);if (password != null && password.equals(oldpqssword)){resultMap.put("result","true");}else{resultMap.put("result","false");}}resp.setContentType("application/json"); // ajax异步请求try {PrintWriter printWriter = resp.getWriter();// JSONArray 阿里巴巴的JSON工具类,转换格式// Map -- > jsonprintWriter.write(JSONArray.toJSONString(resultMap));printWriter.flush();printWriter.close();} catch (IOException e) {e.printStackTrace();}}
}

注意:前面写用户首页登录逻辑时并没有验证密码是否与用户名一致,可以自己加上验证密码功能,很简单。

14.编写用户管理模块

思路:整个项目中的难点。

image-20211211213351264

新建分页的工具类 PageSupport。

public class PageSupport {//当前页码-来自于用户输入private int currentPageNo = 1;//总数量(表)private int totalCount = 0;//页面容量private int pageSize = 0;//总页数-totalCount/pageSize(+1)private int totalPageCount = 1;public int getCurrentPageNo() {return currentPageNo;}public void setCurrentPageNo(int currentPageNo) {if(currentPageNo > 0){this.currentPageNo = currentPageNo;}}public int getTotalCount() {return totalCount;}public void setTotalCount(int totalCount) {if(totalCount > 0){this.totalCount = totalCount;//设置总页数this.setTotalPageCountByRs();}}public int getPageSize() {return pageSize;}public void setPageSize(int pageSize) {if(pageSize > 0){this.pageSize = pageSize;}}public int getTotalPageCount() {return totalPageCount;}public void setTotalPageCount(int totalPageCount) {this.totalPageCount = totalPageCount;}public void setTotalPageCountByRs(){if(this.totalCount % this.pageSize == 0){this.totalPageCount = this.totalCount / this.pageSize;}else if(this.totalCount % this.pageSize > 0){this.totalPageCount = this.totalCount / this.pageSize + 1;}else{this.totalPageCount = 0;}}
}

14.1 获取用户数量,涉及多表查询

// 在UserDaoImpl中添加以下方法
@Override
public int getUserCount(Connection con, String username, int userRole) {PreparedStatement preparedStatement = null;ResultSet rs = null;int count = 0;if (con != null){StringBuffer sql = new StringBuffer();sql.append("select count(1)  as count from smbms_user U,smbms_role R  where U.userRole = R.id");// 前面用Object数组存放占位参数,这里用ArrayList存放List<Object> list = new ArrayList<>();if (username != null && username.length() != 0){sql.append(" and U.userName like ?");list.add("'%" + username + "%'");}if (userRole > 0 && userRole < 4){sql.append(" and U.userRole = ?");list.add(userRole);}Object[] params = list.toArray();System.out.println("UserDaoImpl --> getUserCount : " + sql.toString());try {rs = BaseDao.execute(con,sql.toString(),preparedStatement,rs,params);} catch (SQLException throwables) {throwables.printStackTrace();}try {if (rs.next()){count  = rs.getInt("count");}} catch (SQLException throwables) {throwables.printStackTrace();}try {BaseDao.release(con,preparedStatement,rs);} catch (SQLException throwables) {throwables.printStackTrace();}}return count;
}
// 在UserServiceImpl中添加以下方法
@Override
public int getUserCount(String username,int userRole) {int count = 0;Connection con = BaseDao.getConnection();if (con != null){count = userDao.getUserCount(con,username,userRole);}try {BaseDao.release(con,null,null);} catch (SQLException throwables) {throwables.printStackTrace();}return count;
}

14.2 获取用户列表

代码逻辑和前面差不多:

// 在UserDaoImpl中添加以下方法
@Override
public List<User> getUserList(Connection con, String username, int userRole, int currentPageNo, int pageSize) throws SQLException {List<User> userList  = new ArrayList<>();PreparedStatement preparedStatement = null;ResultSet rs = null;if (con != null){StringBuffer sql = new StringBuffer();sql.append("select u.*,r.roleName as userRoleName from smbms_user u,smbms_role r where u.userRole = r.id");//建一个集合来存储参数List<Object> list = new ArrayList<>();if(username!=null){sql.append(" and u.userName like ?");list.add("%"+username+"%");//默认下标为0}if(userRole>0 & userRole<4){sql.append(" and u.userRole = ?");list.add(userRole);//默认下标为1}//在数据库中 分页使用limit startIndex,pageSize 总数//当前页 = (当前页-1)*页面大小sql.append(" order by u.creationDate DESC limit ?,?");currentPageNo = (currentPageNo-1)*pageSize;list.add(currentPageNo);list.add(pageSize);Object[] params = list.toArray();System.out.println("getUserList的语句"+sql.toString());try {rs =  BaseDao.execute(con,sql.toString(),preparedStatement,rs,params);} catch (SQLException throwables) {throwables.printStackTrace();}while (rs.next()){User user = new User();user.setId(rs.getInt("id"));user.setUserCode(rs.getString("userCode"));user.setUserName(rs.getString("userName"));user.setGender(rs.getInt("gender"));user.setBirthday(rs.getDate("birthday"));user.setPhone(rs.getString("phone"));user.setUserRoleName(rs.getString("userRoleName"));user.setUserRole(rs.getInt("userRole"));userList.add(user);}try {BaseDao.release(con,preparedStatement,rs);} catch (SQLException throwables) {throwables.printStackTrace();}}return userList;
}
// 在UserServiceImpl中添加以下方法
@Override
public List<User> getUserList(String username, int userRole, int currentPageNo, int pageSize) {List<User> userList = new ArrayList<>();Connection con = null;con = BaseDao.getConnection();if (con != null){try {userList = userDao.getUserList(con,username,userRole,currentPageNo,pageSize);} catch (SQLException throwables) {throwables.printStackTrace();}finally {try {BaseDao.release(con,null,null);} catch (SQLException throwables) {throwables.printStackTrace();}}}return userList;
}

14.3 获取用户角色列表(其实属于角色管理模块)

为了职责统一,把角色的操作单独放在一个包中,和POJO相对应。

代码逻辑和前面差不多:

public class RoleDaoImpl implements RoleDao {@Overridepublic List<Role> getRoleList(Connection con) throws SQLException {List<Role> roleList = new ArrayList<>();PreparedStatement preparedStatement = null;ResultSet rs = null;if (con != null){StringBuffer sql = new StringBuffer();sql.append("select * from smbms_role");Object[] params = {};rs = BaseDao.execute(con, sql.toString(), preparedStatement, rs,params);while(rs.next()){Role role = new Role();role.setId(rs.getInt("id"));role.setRoleName(rs.getString("roleName"));role.setRoleCode(rs.getString("roleCode"));roleList.add(role);}BaseDao.release(con,preparedStatement,rs);}return roleList;}
}
public class RoleServiceImpl implements RoleService{//业务层调用持久层private RoleDao roleDao = null;public RoleServiceImpl(){this.roleDao =new RoleDaoImpl();}@Overridepublic List<Role> getRoleList() {List<Role> roleList = new ArrayList<>();Connection con = null;con = BaseDao.getConnection();if (con !=  null){try {roleList = roleDao.getRoleList(con);} catch (SQLException throwables) {throwables.printStackTrace();}finally {try {BaseDao.release(con,null,null);} catch (SQLException throwables) {throwables.printStackTrace();}}}return roleList;}
}

14.4 获取用户显示的servlet

在UserServlet中新添方法。

// 重难点
public void query(HttpServletRequest req,HttpServletResponse resp) {//从前端获取数据 userlist.jspString queryUserName = req.getParameter("queryname");String temp = req.getParameter("queryUserRole");//值为0 、1、2、3String pageIndex = req.getParameter("pageIndex");int queryUserRole = 0;UserServiceImpl userService = new UserServiceImpl();RoleServiceImpl roleService = new RoleServiceImpl();// 设置当前页和页面用户数量int currentPageNo = 1;int pageSize = 5;if (queryUserName == null) {queryUserName = "";}if (temp != null && !temp.equals("")) {queryUserRole = Integer.parseInt(temp);}if (pageIndex != null) {currentPageNo = Integer.parseInt(pageIndex);}System.out.println("queryUserName : " + queryUserName + ", queryUserRole : " + queryUserRole);int totalCount = userService.getUserCount(queryUserName, queryUserRole);PageSupport pageSupport = new PageSupport();pageSupport.setCurrentPageNo(currentPageNo);pageSupport.setPageSize(pageSize);pageSupport.setTotalCount(totalCount);int totalPageCount = pageSupport.getTotalPageCount();//控制首页和尾页//如果页数小于1,就显示第一页  页数大于 最后一页就 显示最后一页if (currentPageNo < 1) {currentPageNo = 1;} else if (currentPageNo > totalPageCount) {currentPageNo = totalPageCount;}// 获取用户列表展示,传给前端展示List<User> userList = userService.getUserList(queryUserName, queryUserRole, currentPageNo, pageSize);req.getSession().setAttribute("userList",userList);for (User u : userList){System.out.println(u.getUserName());}List<Role> roleList = roleService.getRoleList();req.getSession().setAttribute("roleList",roleList);req.getSession().setAttribute("totalCount",totalCount);req.getSession().setAttribute("currentPageNo",currentPageNo);req.getSession().setAttribute("totalPageCount",totalPageCount);req.getSession().setAttribute("queryUserName",queryUserName);req.getSession().setAttribute("queryUserRole",queryUserRole);try {req.getRequestDispatcher("userlist.jsp").forward(req,resp);} catch (ServletException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}
}

14.5 用户管理模块 子模块—添加用户功能

一切的增删改操作都需要处理事务!

先写完dao层的实现类:

@Override
public int addUser(Connection con, User user) {int count = 0;PreparedStatement preparedStatement = null;if (con != null){String sql = "insert into smbms_user (userCode,userName,userPassword,gender,birthday,phone,address,userRole,createdBy,creationDate)values(?,?,?,?,?,?,?,?,?,?)";Object[] params ={user.getUserRole(),user.getUserName(),user.getUserPassword(),user.getGender(),user.getBirthday(),user.getPhone(),user.getAddress(),user.getUserRole(),user.getCreatedBy(),user.getCreationDate()};try {count = BaseDao.execute(con,sql,preparedStatement,params);} catch (SQLException throwables) {throwables.printStackTrace();}finally {//try {//    BaseDao.release(con,preparedStatement,null);//} catch (SQLException throwables) {//    throwables.printStackTrace();//}}}return count;
}

再来写service层的实现类:注意开启事务!

@Override
public boolean addUser(User user) {Connection conn = null;boolean flag = false;try {//获取数据库连接conn = BaseDao.getConnection();//开启JDBC事务管理conn.setAutoCommit(false);//Service层调用dao层的方法添加用户int updateRows = userDao.addUser(conn, user);conn.commit();if(updateRows > 0){flag = true;}} catch (SQLException e) {e.printStackTrace();conn.rollback();}finally {//释放连接//try {//    BaseDao.release(conn, null, null);//} catch (SQLException throwables) {//    throwables.printStackTrace();//}return flag;}
}

在可重用Servlet类中添加判断用户编码是否存在的方法。

// 用户管理模块 子模块(验证用户编码是否已经存在)
public void ifExist(HttpServletRequest req, HttpServletResponse resp){//获取前端输入 的用户编码String userCode = req.getParameter("userCode");UserServiceImpl userService = new UserServiceImpl();Boolean flag = userService.getUser(userCode);//将结果存放在map集合中 让Ajax使用Map<String, String> resultMap = new HashMap<>();if (flag){resultMap.put("userCode","exist");}//上面已经封装好 现在需要传给Ajax 格式为json 所以我们得转换格式resp.setContentType("application/json");//将应用的类型变成jsonPrintWriter writer = null;try {writer = resp.getWriter();} catch (IOException e) {e.printStackTrace();}//JSONArray 阿里巴巴的JSON工具类 用途就是:转换格式writer.write(JSONArray.toJSONString(resultMap));writer.flush();writer.close();
}

添加用户BUG修复:

添加用户提交后,出现如下错误:

No operations allowed after connection closed。

解决方案:

把释放数据库连接的相关代码都注释掉。

经验总结:之后牵涉到事务的代码都要这样处理!

14.6 用户管理模块 子模块—删除用户功能

思路和前面类似,从底层往上写。

Dao层实现类:

@Override
public int deleUser(Connection con, int userId) {int count = 0;PreparedStatement preparedStatement = null;if (con != null){String sql = "delete from smbms_user where id = ?";Object[] params = {userId};try {count = BaseDao.execute(con,sql,preparedStatement,params);} catch (SQLException throwables) {throwables.printStackTrace();}}return count;
}

UserService层实现类:

@Override
public boolean deleUser(int userId) {boolean flag = false;Connection con  = BaseDao.getConnection();try {//开启JDBC事务管理con.setAutoCommit(false);//Service层调用dao层的方法添加用户int updateRows = userDao.deleUser(con, userId);con.commit();if(updateRows > 0){flag = true;}} catch (SQLException throwables) {throwables.printStackTrace();}return flag;
}

Servlet层:

private void deleUser(HttpServletRequest req, HttpServletResponse resp) {//从前端获取 要删除的用户 的信息String userid = req.getParameter("uid");int delId = 0;//先转换try {delId = Integer.parseInt(userid);}catch (Exception e){e.printStackTrace();delId = 0;}//将结果存放在map集合中 让Ajax使用Map<String, String> resultMap = new HashMap<>();if(delId<=0){resultMap.put("delResult","notexist");}else {UserServiceImpl userService = new UserServiceImpl();if(userService.deleUser(delId)){resultMap.put("delResult","true");}else {resultMap.put("delResult", "false");}}//上面已经封装好 现在需要传给Ajax 格式为json 所以我们得转换格式resp.setContentType("application/json");//将应用的类型变成jsonPrintWriter writer = null;try {writer = resp.getWriter();} catch (IOException e) {e.printStackTrace();}//JSONArray 阿里巴巴的JSON工具类 用途就是:转换格式writer.write(JSONArray.toJSONString(resultMap));writer.flush();writer.close();
}

14.7 用户管理模块 子模块—修改用户信息功能

思路和前面类似,从底层往上写。

Dao层实现类:

这里增加一个getUserById方法来查询 旧数据 ,并显示在修改的页面中。

@Override
public int modifyUser(Connection conn, User user) throws SQLException {int count = 0;PreparedStatement preparedStatement = null;if (conn != null){String sql = "update smbms_user set userName=?,"+"gender=?,birthday=?,phone=?,address=?,userRole=?,modifyBy=?,modifyDate=? where id = ? ";Object[] params = {user.getUserName(),user.getGender(),user.getBirthday(),user.getPhone(),user.getAddress(),user.getUserRole(),user.getModifyBy(),user.getModifyDate(),user.getId()};try {count = BaseDao.execute(conn,sql,preparedStatement,params);} catch (SQLException throwables) {throwables.printStackTrace();}}return count;
}@Override
public User getUserById(Connection con, String id) throws Exception {User user = null;PreparedStatement pstm = null;ResultSet rs = null;if(null != con){String sql = "select u.*,r.roleName as userRoleName from smbms_user u,smbms_role r where u.id=? and u.userRole = r.id";Object[] params = {id};rs = BaseDao.execute(con, sql, pstm, rs, params);if(rs.next()){user = new User();user.setId(rs.getInt("id"));user.setUserCode(rs.getString("userCode"));user.setUserName(rs.getString("userName"));user.setUserPassword(rs.getString("userPassword"));user.setGender(rs.getInt("gender"));user.setBirthday(rs.getDate("birthday"));user.setPhone(rs.getString("phone"));user.setAddress(rs.getString("address"));user.setUserRole(rs.getInt("userRole"));user.setCreatedBy(rs.getInt("createdBy"));user.setCreationDate(rs.getTimestamp("creationDate"));user.setModifyBy(rs.getInt("modifyBy"));user.setModifyDate(rs.getTimestamp("modifyDate"));user.setUserRoleName(rs.getString("userRoleName"));}BaseDao.release(null, pstm, rs);}return user;
}

UserService层实现类:

@Override
public boolean modifyUser(User user) {Connection connection = null;boolean flag = false;try {connection = BaseDao.getConnection();connection.setAutoCommit(false);if(userDao.modifyUser(connection,user) > 0)flag = true;connection.commit();} catch (Exception e) {// TODO Auto-generated catch blocke.printStackTrace();}return flag;
}@Override
public User getUserById(String id) throws SQLException {User user = null;Connection connection = null;try{connection = BaseDao.getConnection();user = userDao.getUserById(connection,id);}catch (Exception e) {// TODO: handle exceptione.printStackTrace();user = null;}finally{BaseDao.release(connection, null, null);}return user;
}

Servlet层方法:

private void findById(HttpServletRequest req, HttpServletResponse resp,String url) throws ServletException, IOException {//从前端获取 要修改的用户 的idString uid = req.getParameter("uid");if (uid != null && uid.length() != 0){UserServiceImpl userService = new UserServiceImpl();//查询要更改的用户信息User user = null;try {user = userService.getUserById(uid);} catch (SQLException throwables) {throwables.printStackTrace();}//将用户信息保存至 request中 让usermodify.jsp显示req.setAttribute("user",user);req.getRequestDispatcher(url).forward(req,resp);}
}private void modifyUser(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException {String id = request.getParameter("uid");String userName = request.getParameter("userName");String gender = request.getParameter("gender");String birthday = request.getParameter("birthday");String phone = request.getParameter("phone");String address = request.getParameter("address");String userRole = request.getParameter("userRole");User user = new User();user.setId(Integer.valueOf(id));user.setUserName(userName);user.setGender(Integer.valueOf(gender));try {user.setBirthday(new SimpleDateFormat("yyyy-MM-dd").parse(birthday));} catch (ParseException e) {// TODO Auto-generated catch blocke.printStackTrace();}user.setPhone(phone);user.setAddress(address);user.setUserRole(Integer.valueOf(userRole));user.setModifyBy(((User)request.getSession().getAttribute(Constant.USER_SESSION)).getId());user.setModifyDate(new Date());UserService userService = new UserServiceImpl();if(userService.modifyUser(user)){response.sendRedirect(request.getContextPath()+"/jsp/user.do?method=query");}else{request.getRequestDispatcher("usermodify.jsp").forward(request, response);}
}

14.8 用户管理模块 子模块—查看用户信息功能

思路和前面类似,从底层往上写。

这里直接利用修改用户用到的getUserById方法,之前修改用户用到两个方法,先查看原有用户信息,然后再修改用户信息。

这里就不用再写了。

只要用一个参数将修改用户信息和查看用户信息的操作分别重定向到对应的页面就行。


至此,用户的所有操作都已经实现了。

后面的订单管理和供应商管理等模块功能类似,这里就不再重复了,直接看源码。

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

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

相关文章

【日常记录】【插件】excel.js导出的时候给单元格设置下拉选择、数据校验等

文章目录 1. 代码基本结构2. 导出的excel 某单元格的值设置为下拉选择3. 如何把下拉选择项设置为动态4. 单元格设置校验、提示5. 在WPS上的设置 1. 代码基本结构 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><…

韦东山嵌入式linux系列-驱动进化之路:设备树的引入及简明教程

1 设备树的引入与作用 以 LED 驱动为例&#xff0c;如果你要更换LED所用的GPIO引脚&#xff0c;需要修改驱动程序源码、重新编译驱动、重新加载驱动。 在内核中&#xff0c;使用同一个芯片的板子&#xff0c;它们所用的外设资源不一样&#xff0c;比如A板用 GPIO A&#xff0c…

基于python的京东VR眼镜口碑情感分析,包括lda和情感分析

第1章 绪论 1.1选题背景 在当今科技发展迅速的时代&#xff0c;虚拟现实&#xff08;VR&#xff09;技术作为一种前沿的数字体验方式受到越来越多人的关注。京东作为中国领先的电商平台&#xff0c;推出的VR眼镜备受消费者关注。通过对京东VR眼镜口碑进行情感分析&#xff0c…

Pycharm 报错 Environment location directory is not empty 解

删除项目中ven文件夹&#xff08;已存在的&#xff09;&#xff0c;然后再添加新的ven虚拟环境就可以了

如何用手机压缩视频?手机压缩视频方法来了

高清视频的大文件大小常常成为分享和存储的障碍&#xff0c;尤其是在数据流量有限或存储空间紧张的情况下。幸运的是&#xff0c;无论是智能手机还是个人电脑&#xff0c;都有多种方法可以帮助我们轻松压缩视频文件&#xff0c;以适应不同的需求和情境。本文将介绍如何在手机上…

格式工厂转换视频分辨率

1、下载和安装 http://www.pcfreetime.com/formatfactory/CN/index.html 2、打开视频 3、设置分辨率等参数 也可以选择保持原分辨率 4、执行导出 5、打开输出所在位置

前端开发之盒子模型

目录 盒子分类 display属性 盒子内部结构特征 padding填充区 border边框区 margin外边距 盒子width和height边界 盒子分类 块级盒子&#xff08;又叫块级元素、块级标签&#xff09; 特征&#xff1a;独占一行&#xff0c;对宽度高度支持 如&#xff1a;p div ul li h1…

完整且详细的Yolov8复现+训练自己的数据集

Yolov8 的源代码下载&#xff1a;ultralytics/ultralytics: NEW - YOLOv8 &#x1f680; in PyTorch > ONNX > CoreML > TFLite (github.com)https://github.com/ultralytics/ultralytics Yolov8的权重下载&#xff1a;Releases ultralytics/assets GitHubUltralyt…

Java 反射机制:概念、用途与示例

个人名片 &#x1f393;作者简介&#xff1a;java领域优质创作者 &#x1f310;个人主页&#xff1a;码农阿豪 &#x1f4de;工作室&#xff1a;新空间代码工作室&#xff08;提供各种软件服务&#xff09; &#x1f48c;个人邮箱&#xff1a;[2435024119qq.com] &#x1f4f1…

Spring纯注解开发

前言 Spring3.0引入了纯注解开发的模式&#xff0c;框架的诞生是为了简化开发&#xff0c;那注解开发就是简化再简化。Spring的特性在整合MyBatis方面体现的淋漓尽致哦 一.注解开发 以前跟老韩学习SE时他就说&#xff1a;注解本质是一个继承了Annotation 的特殊接口,其具体实…

智慧农业新纪元:解锁新质生产力,加速产业数字化转型

粮食安全乃国家之根本&#xff0c;“浙江作为农业强省、粮食生产重要省份&#xff0c;在维护国家粮食安全大局中肩负着重大使命。浙江粮食产业经济年总产值已突破4800亿元&#xff0c;稳居全国前列&#xff0c;然而&#xff0c;同样面临着规模大而不强、质量效益有待提升、数字…

C语言 ——— 打印水仙花数

目录 何为水仙花数 题目要求 代码实现 何为水仙花数 “水仙花数”是指一个n位数&#xff0c;其各位数字的n次方之和等于该数本身 如&#xff1a;153 1^3 5^3 3^3&#xff0c;则153就是一个“水仙花数” 题目要求 求出0~100000的所有“水仙花数”并输出 代码实现 #i…

人工智能算法工程师(高级)课程1-单类目标识别之人脸检测识别技术MTCNN模型介绍与代码详解

大家好&#xff0c;我是微学AI&#xff0c;今天给大家介绍一下人工智能算法工程师(高级)课程1-单类目标识别之人脸检测识别技术MTCNN模型介绍与代码详解。本文深入探讨了基于PyTorch的人脸检测与识别技术&#xff0c;详细介绍了MTCNN模型、Siamese network以及center loss、sof…

PostgreSQL创建表和自增序列

一、创建表&#xff1a; 注意&#xff1a; 1、在mysql没有序列的概念&#xff0c;id自增通过auto_increment实现&#xff1b; 2、pgsql没有auto_increment的概念&#xff0c;如何实现id自增&#xff1f;有两种方式&#xff1a; 方式一&#xff1a;创建序列&#xff0c;绑定…

2024年海峡两岸创业青年研学交流项目火热开展中

7月17日&#xff0c;由浙江外国语学院国际商学院、创业学院主办的“文化之舟系两岸&#xff0c;潮头勇立浙商旗”——2024年海峡两岸大学生&#xff08;创业青年&#xff09;研学交流项目持续进行中。 上午&#xff0c;邵波副教授带领学生代表接待来自台湾的二十多名学生参加“…

【人工智能】在未来智慧城市的建设及应用分析

作者主页: 知孤云出岫 目录 作者主页:案例分析&#xff1a;人工智能在未来智慧城市的建设及其影响和应用引言一、人工智能在智慧城市中的关键应用领域 案例分析&#xff1a;人工智能在未来智慧城市的建设及其影响和应用 引言 智慧城市是利用信息和通信技术&#xff08;ICT&am…

迁移学习在乳腺浸润性导管癌病理图像分类中的应用

1. 引言 乳腺癌主要有两种类型:原位癌:原位癌是非常早期的癌症&#xff0c;开始在乳管中扩散&#xff0c;但没有扩散到乳房组织的其他部分。这也称为导管原位癌(DCIS)。浸润性乳腺癌:浸润性乳腺癌已经扩散(侵入)到周围的乳腺组织。侵袭性癌症比原位癌更难治愈。将乳汁输送到乳…

Kafka Producer之幂等性

文章目录 1. 启用幂等性2. 底层变化3. 数据不重复4. 数据有序 幂等性通过消耗时间和性能的方式&#xff0c;解决乱序和重复问题。 但是只能保证同一生产者在一个分区中的幂等性。 1. 启用幂等性 //创建producerHashMap<String, Object> config new HashMap<>();…

怎样在 PostgreSQL 中优化对大表的分区裁剪和索引选择?

&#x1f345;关注博主&#x1f397;️ 带你畅游技术世界&#xff0c;不错过每一次成长机会&#xff01;&#x1f4da;领书&#xff1a;PostgreSQL 入门到精通.pdf 文章目录 怎样在 PostgreSQL 中优化对大表的分区裁剪和索引选择一、分区裁剪&#xff1a;精准切割&#xff0c;提…

【自学安全防御】三、企业双机热备和带宽管理的综合实验

实验拓扑&#xff1a; 实验任务&#xff1a; 12&#xff0c;对现有网络进行改造升级&#xff0c;将当个防火墙组网改成双机热备的组网形式&#xff0c;做负载分担模式&#xff0c;游客区和DMZ区走FW3&#xff0c;生产区和办公区的流量走FW1 13&#xff0c;办公区上网用户限制流…