超市订单管理系统(smbms)——后端开发

背景

学习b站up遇见狂神说JavaWeb相关视频做的项目,本人开发经验比较少,不喜勿喷,讲的是一些开发准备还有过程中遇到的一些问题。

前期环境搭建

  • MySQL下载,环境搭建和可视化工具,这里用的是NaviCat
  • TomCat下载和环境搭建,这里用的是TomCat10.0.10
  • 新建Maven搭建工程,这里用的是模板创建webapp项目

遇到的一些问题:

  • MySQL初始化成功,但是无法进入可视化工具,即使用户名和密码正确的情况下,报错the user specified as a definer (‘mysql.infoschema’@‘localhost’) dose not exist,通过百度查询得到结果是缺少一个mysql.infoschema@locaclhost用户,因此根据用户提示需求新建用户,并赋予数据库的所有权限即可解决问题,如下图所示:

在这里插入图片描述

在这里插入图片描述

  • 因为采用Tomcat10的缘故,部分包会更改名字,如果仍旧采用原先的名字则会无法运行,如使用到HttpServlet的地方,老版本的包名是javax.servlet.xxxx,新版本的包名是jakarta.servlet.xxxx,诸如此类的问题还有一些,因为我的项目中只用到了servlet,jstl,mysql和json,本人用到的包是以下这些(可能有多余的没有用的)
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>jakarta.servlet</groupId>
      <artifactId>jakarta.servlet-api</artifactId>
      <version>5.0.0</version>
    </dependency>
    <dependency>
      <groupId>org.glassfish.web</groupId>
      <artifactId>jakarta.servlet.jsp.jstl</artifactId>
      <version>2.0.0</version>
    </dependency>
    <dependency>
      <groupId>org.apache.taglibs</groupId>
      <artifactId>taglibs-standard-spec</artifactId>
      <version>1.2.5</version>
    </dependency>
    <dependency>
      <groupId>org.apache.taglibs</groupId>
      <artifactId>taglibs-standard-impl</artifactId>
      <version>1.2.5</version>
    </dependency>
    <dependency>
      <groupId>org.junit.jupiter</groupId>
      <artifactId>junit-jupiter</artifactId>
      <version>RELEASE</version>
      <scope>compile</scope>
    </dependency>
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>8.0.26</version>
    </dependency>
    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>fastjson</artifactId>
      <version>1.2.59</version>
    </dependency>
  </dependencies>

Java代码准备

根据MVC三层架构创建以下文件结构:

在这里插入图片描述

dao用来编写对于数据库操作的代码,filter用来存储过滤器,pojo则是写实体类(每一个实体类对应一个数据库),service则是编写相应的服务(如增删改等),servlet则是编写对于前端发来的请求的处理代码,util则是项目过程中用到的一些工具类(在本项目中使用Constants存放一些固定属性,用PageSupport协助分页的实现);

最底层的数据库操作类代码:

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");
        //这里需要加上getClassLoader()方法,不然代码会运行不了,但是编译正常(印象中编译是正常的)
        try {
            properties.load(is);
        } catch (IOException e) {
            e.printStackTrace();
        }
        //这里是从配置文件中读取的数据,即db.properties文件
        driver = properties.getProperty("driver");
        url = properties.getProperty("url");
        username = properties.getProperty("username");
        password = properties.getProperty("password");
    }

    //获得数据库连接
    public static Connection getConnection() {
        Connection connection = null;
        //1. 注册驱动
        try {
            Class.forName(driver);
            connection = DriverManager.getConnection(url,username,password);
        } catch (ClassNotFoundException | SQLException e) {
            e.printStackTrace();
        }
        return connection;
    }

    //查询的sql方法
    public static ResultSet executeQuery(Connection conn, String sql, Object[] params, ResultSet rs,PreparedStatement preSta) throws SQLException {
        //查询方法
        //这里的sql是没有完全填写完整的sql
        //需要通过params进行参数填充
        preSta = conn.prepareStatement(sql);
        for (int i=0;i<params.length;i++){
            preSta.setObject(i+1,params[i]);
            //sql语句中,索引应该从1开始
        }
        rs = preSta.executeQuery();
        return rs;
        //这里的resultSet已经作为了参数传进来一遍,但又作为返回值传出去?
    }

    //增删改的sql方法
    public static int execute(Connection conn,String sql,Object[] params,PreparedStatement preSta) throws SQLException {
        preSta = conn.prepareStatement(sql);
        for (int i=0;i<params.length;i++){
            preSta.setObject(i+1,params[i]);
            //sql语句中,索引应该从1开始
        }
        int ans = preSta.executeUpdate();
        return ans;
    }

    //释放连接资源
    public static boolean realease(Connection conn,ResultSet rs,PreparedStatement preSta){
        boolean flag = true;
        if (conn!=null){
            try {
                conn.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
                flag = false;
            }
        }
        if (rs!=null){
            try {
                rs.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
                flag = false;
            }
        }
        if (preSta!=null){
            try {
                preSta.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
                flag = false;
            }
        }
        return flag;
    }
}
driver=com.mysql.cj.jdbc.Driver		#以前的版本是com.mysql.jdbc.Driver,现在是com.mysql.cj.jdbc.Driver,又是版本
url=jdbc:mysql://localhost:3306/smbms?userUnicode=true&&characterEncoding=utf-8
username=root
password=123456

过滤器代码(实现Encoding过滤和登录过滤)

public class CharacterEncodingFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        servletRequest.setCharacterEncoding("utf-8");
        servletResponse.setCharacterEncoding("utf-8");
        filterChain.doFilter(servletRequest,servletResponse);
    }

    @Override
    public void destroy() {

    }
}

public class JspFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public 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(Constants.USER_SESSION);
        //根据自己的文件地址进行设置
        if (user == null){
            resp.sendRedirect(req.getContextPath()+"/login.jsp");
        }else{
            filterChain.doFilter(servletRequest,servletResponse);
        }

    }

    @Override
    public void destroy() {

    }
}

实体类代码(这里本来我是对照数据库操作的,即没有加上对应的外键的名字——没有设置外键只是这么叫方便理解,后来在调试的时候发现前端实际上写了相应的代码,即要求传回一个billList,同时含有属性providerName,被迫修改前面的代码。开发过程中前端和后端应该是会商量好要用到的所有变量名,调用某个方法接收的返回值类型,等等,但我是拿别人开源的项目自己做后端所以就出现了一些问题)

public class Bill {
    private Integer id;
    private String billCode;
    private String productName;
    private String productDesc;
    private String productUnit;
    private BigDecimal productCount;
    private BigDecimal totalPrice;
    private Integer isPayment;
    private Integer createBy;
    private Date creationDate;
    private Integer modifyBy;
    private Date modifyDate;
    private String providerName;
}

public class Provider {

    private Integer id;
    private String proCode;
    private String proName;
    private String proDesc;
    private String proContact;
    private String proPhone;
    private String proAddress;
    private String proFax;
    private Integer createBy;
    private Date creationDate;
    private Integer modifyBy;
    private Date modifyDate;
}

public class Role {

    private Integer id;
    private String roleCode;
    private String roleName;
    private Integer createBy;
    private Date creationDate;
    private Integer modifyBy;
    private Date modifyDate;
}

public class User {

    private Integer id;
    private String userCode;
    private String userName;
    private String userPassword;
    private Integer gender;
    private Date birthday;      //这里其实我并不确定是java工具类的Date还是数据库的Date
    private String phone;
    private String address;
    private Integer userRole;
    private Integer createBy;
    private Date creationDate;
    private Integer modifyBy;
    private Date modifyDate;
    private Integer age;
    private String userRoleName;
}

项目使用到的常量和一些工具类:

public class Constants {
    public static final String USER_SESSION = "USER_SESSION";
    public static final String SYS_MESSAGE = "SYS_MESSAGE";
    public static final int PAGE_SIZE = 5;
}

public class PageSupport {
    private int totalCount = 0;
    private int pageSize = Constants.PAGE_SIZE;
    private int totalPageCount = 1;

    public PageSupport(int totalCount){
        this.totalCount = totalCount;
        double temp = (double)pageSize;
        totalPageCount = (int) Math.ceil(totalCount/temp)>0?(int) Math.ceil(totalCount/temp):1;
    }

    public int getTotalCount() {
        return totalCount;
    }

    public void setTotalCount(int totalCount) {
        this.totalCount = totalCount;
        double temp = (double)pageSize;
        totalPageCount = (int) Math.ceil(totalCount/temp)>0?(int) Math.ceil(totalCount/temp):1;
    }

    public int getPageSize() {
        return pageSize;
    }

    public int getTotalPageCount() {
        return totalPageCount;
    }

}

数据库相关准备

Create table smbms_address if not exists(	-- 事实上这张表并没有用到 --
	id bigint(20) not null auto_increment comment '主键ID',
	contact varchar(15) collate utf8_unicode_ci not null comment '联系人姓名',
	addressDesc varchar(50) collate utf8_unicode_ci not null comment '收货地址明细',
	postCode varchar(15) collate utf8_unicode_ci default null comment '邮编',
	tel varchar(20) collate utf8_unicode_ci not null comment '联系人电话',
	createBy 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=1 default charset=utf8 collate=utf8_unicode_ci;

create table smbms_bill if not exists(
	id bigint(20) not null auto_increment comment '主键id',
	billCode varchar(20) collate utf8_unicode_ci not null comment '账单编码',
	productName varchar(20) collate utf8_unicode_ci not null comment '商品名称',
	productDesc varchar(50) collate utf8_unicode_ci default null comment '商品描述',
	productUnit varchar(10) collate utf8_unicode_ci not null comment '商品单位',
	productCount decimal(20,2) not null comment '商品数量',
	totalPrice decimal(20,2) not null comment '商品总额',
	isPayment int(10) not null comment '是否支付(1:未支付 2:已支付)',
	createBy bigint(20) default null comment '创建者(userId)',
	creationDate datetime default null comment '创建时间',
	modifyBy bigint(20) default null comment '更新者(userId)',
	modifyDate datetime default null comment '更新时间',
	providerId int(20) default null comment '供应商id',
	primary key(id)
)engine=InnoDB auto_increment=1 default charset=utf8 collate=utf8_unicode_ci;

create table smbms_provider(
	id bigint(20) not null auto_increment comment '主键id',
	proCode varchar(20) collate utf8_unicode_ci not null comment '供应商编码',
	proName varchar(20) collate utf8_unicode_ci not null comment '供应商名称',
	proDesc varchar(50) collate utf8_unicode_ci default null comment '供应商详细描述',
	proContact varchar(20) collate utf8_unicode_ci not null comment '供应商联系人',
	proPhone varchar(20) collate utf8_unicode_ci not null comment '联系电话',
	proAddress varchar(50) collate utf8_unicode_ci not null comment '地址',
	proFax varchar(20) collate utf8_unicode_ci default null comment '传真',
	createBy 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=1 default charset=utf8 collate=utf8_unicode_ci;

create table smbms_role(
	id bigint(20) not null auto_increment comment '主键id',
	roleCode varchar(15) collate utf8_unicode_ci not null comment '角色编码',
	roleName varchar(15) collate utf8_unicode_ci not null comment '角色名称',
	createBy 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=1 default charset=utf8 collate=utf8_unicode_ci;

create table smbms_user(
	id bigint(20) not null auto_increment comment '主键id',
	userCode varchar(15) collate utf8_unicode_ci not null comment '用户编码',
	userName varchar(15) collate utf8_unicode_ci not null comment '用户名称',
	userPassword varchar(15) collate utf8_unicode_ci not null comment '用户密码',
	gender int(10) default 1 comment '性别(1:女 2:男)',
	birthday date default null comment '出生日期',
	phone varchar(15) collate utf8_unicode_ci not null comment '联系电话',
	address varchar(30) collate utf8_unicode_ci not null comment '地址',
	userRole int(10) default null comment '用户角色(取自角色表)',
	createBy 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=1 default charset=utf8 collate=utf8_unicode_ci;

相关添加记录语句并没有保存下来,详细内容可以查看这位博主的。超市订单管理系统_xiqsun0的博客-CSDN博客

开发过程

开发的步骤应该是这样的:

  • 研究相关jsp文件和js文件(有可能有ajax请求)中是否发送了http请求,如果是,根据请求需要返回的数据做业务实现;
  • 先从Dao层的代码开始编写,实现相应功能的部分返回值要求,也可能是全部,如添加功能只需要一个方法就可以实现,但用户管理功能需要搜索和分页多个功能,此时Dao层需要根据需求编写多个方法;
  • 完成Dao层代码编写,接着开始完成Service层的代码,一般都是一些比较模板化的代码,但在像动态搜索这种功能的实现中,可能需要判断参数,具体的开始写代码就知道了;
  • 完成Service层代码编写,可以写控制层代码,即Servlet,根据功能实现的需求进行设置相应的参数,并选择使用重定向或者请求转发的方式将相应的参数返回,如果是ajax请求则是json格式的数据,另外,在ajax中,重定向和请求转发的代码是不会生效的;
  • 注册Servlet,运行查看代码效果,如果有bug就debug,如果没有就进行下一个模块的开发。

遇到的一些问题

  • 在传递用户管理界面所需要的参数的时候,如UserList的时候,由于只设置了数据库中的相应字段,如Role字段只设置了相应的RoleId而没有设置Name属性,因此前端接收参数的时候出现了问题,属于是没有搞明白前端的参数需求,然后这方面的话,个人认为应该属于开发前期需要前后端一起协定的,或者自己独立开发,把所有需要用到的变量都统一了。
  • 在设计用户管理界面的删除功能的时候,通过点击用户的相应图标按钮即可实现删除,因为用户页面是实现了分页的,但是删除后不会自动补全(即把下一页的第一个内容补充到上一页),仔细研究前端的设置即可看明白事实上后端只传递了设置的分页数大小的数据,而不是动态的,但是ajax中不会处理请求转发和重定向的代码,所以无法通过再次请求相应的数据做到动态删除,因此没做处理,但是这个时候就会发现删除后的url那里莫名其妙多了一个"#",就很奇怪,但是没有仔细研究。
  • 关于动态删除的问题,可以在原先的ajax中嵌套一个ajax,将原先分页需要的参数封装成json数据格式传回来,然后再设置到页面中。但是我在尝试的时候,发现从jsp中传递参数到js时,js中死活都接收不到,所以就放弃了。
  • 还有一些七七八八的MySQL语句编写异常,传递参数时空指针异常,json数据键名设置错误等,在此不一一介绍。

代码

five517/SMBMS at master (github.com)

这一个是我自己在找开源代码的时候发现的,然后算是资源比较齐全的一份。

rglzy/smbms (github.com)

这一个是我自己完成的项目代码,嗯……也算是完成度比较高的吧(至少前端要求实现的功能都实现了),然后基本上没怎么改动,差别应该不大。前端代码有一些问题,具体的可以参考上面的part。

  • 1
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值