【项目实践】SMBMS(Javaweb版)汇总版

文章目录

前期准备工作

数据库、数据表

设计ER图,考虑需求逻辑,设计表结构,一般格式使用utf8。

确定使用的数据库,安装MySQL。navicat或Dbeaver 操作数据库。

本地练习的数据库选用MySQL,账号密码使用root

创建web项目

安装IDE开发工具:idea/eclipse

配置maven,jdk,tomcat;

maven 更改setting.xml中的路径源,调整为国内的内容。

使用idea创建一个maven web 项目,配置下tomcat,启动下看看是否正常。

创建项目文件目录

明确当前是属于javaweb项目,需要使用servlet进行交互。

创建目录结构

  • src
    • main
      • java
        • com
          • common
            • Constants.java //共通常量
            • utils // 共同使用的软件包
          • thisprojiect
            • dao //与数据库交互的持久层
            • pojo // javaBean实体类
            • sevice // 实现逻辑的业务逻辑层
            • servlet // 处理请求转发实现相关功能
            • filter // 拦截器,处理数据编码
      • resources //配置文件路径
      • webapp // 网站资源
        • WEB-INF // 网站信息
        • index.jsp
    • test // 测试目录

配置Tomcat,导入依赖

将需要用到几种依赖环境,一定要及时更新,

  • javax.servlet-api
  • javax.servlet.jsp-api
  • mysql-connector-java
  • jstl-api // jstl的接口和标签规范
  • standard // jstl的具体实现

确保 jstl 和 standard 的版本一致

xml 复制代码
<dependencies>
  <!--    servlet-->
  <dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>4.0.1</version>
  </dependency>
  <!--    jsp-->
  <dependency>
    <groupId>javax.servlet.jsp</groupId>
    <artifactId>javax.servlet.jsp-api</artifactId>
    <version>2.3.3</version>
  </dependency>
  <!--      mysql-->
  <dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.24</version>
  </dependency>
  <!--    JSTL表达式-->
  <dependency>
    <groupId>javax.servlet.jsp.jstl</groupId>
    <artifactId>jstl-api</artifactId>
    <version>1.2</version>
  </dependency>
  <!--      standard-->
  <dependency>
    <groupId>taglibs</groupId>
    <artifactId>standard</artifactId>
    <version>1.1.2</version>
  </dependency>
</dependencies>

建立实体类

根据前面设计的表结构,作成javaBean。

生成相对应的getter,setter方法

编写javabean的时候要注意数据类型。

目录:src.java.com.myprojiect.pojo

java 复制代码
package com.dashangms.pojo;

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 createDate; // 创建时间
    private Integer modifyBy;   //更新者
    private Date modifyDate;    //更新时间

    private Integer age;    //年龄
    private String userRoleName;    //用户角色名称

    public User() {
    }


    public Integer getAge() {
        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 getCreateDate() {
        return createDate;
    }

    public void setCreateDate(Date createDate) {
        this.createDate = createDate;
    }

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

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", userCode='" + userCode + '\'' +
                ", userName='" + userName + '\'' +
                ", userPassword='" + userPassword + '\'' +
                ", gender=" + gender +
                ", birthday=" + birthday +
                ", phone='" + phone + '\'' +
                ", address='" + address + '\'' +
                ", userRole=" + userRole +
                ", createdBy=" + createdBy +
                ", createDate=" + createDate +
                ", modifyBy=" + modifyBy +
                ", modifyDate=" + modifyDate +
                ", age=" + age +
                ", userRoleName='" + userRoleName + '\'' +
                '}';
    }
}

编写基础公共方法类

数据库交互需要用到的方法

目录:src.java.com.myprojiect.dao

不要忘记需要先加载数据库配置文件,写入static静态方法中;

数据库交互会有以下几种场合:

  • 数据库连接
  • 数据库关闭
  • 数据库查询:查询功能
  • 数据库更新:增删改功能

做好异常保护,try ... catch...

java 复制代码
package com.dashangms.dao;

import java.io.InputStream;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
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 properties = new Properties();
        // 通过类加载器获取配置文件输入流
        InputStream inputStream = BaseDao.class.getClassLoader().getResourceAsStream("db.properties");
        // 尝试加载配置文件并获取数据库连接属性
        try {
            // 加载配置文件到Properties对象
            properties.load(inputStream);
            // 从Properties对象中获取数据库驱动属性
            driver = properties.getProperty("driver");
            // 从Properties对象中获取数据库URL属性
            url = properties.getProperty("url");
            // 从Properties对象中获取数据库用户名属性
            username = properties.getProperty("username");
            // 从Properties对象中获取数据库密码属性
            password = properties.getProperty("password");
        } catch (Exception e) {
            // 打印异常信息,便于调试和日志记录
            e.printStackTrace();
        }
    }

    /**
     * 获取数据库连接
     * <p>
     * 此方法旨在建立与特定数据库的连接,使用预定义的驱动程序、URL、用户名和密码
     * 它封装了数据库连接的创建过程,对外提供了一个简单的接口
     *
     * @return Connection 数据库连接对象如果无法建立连接,则返回null
     */
    public static Connection connection() {
        Connection connection = null;
        try {
            // 加载并注册JDBC驱动程序
            Class.forName(driver);
            // 使用指定的URL、用户名和密码建立数据库连接
            connection = java.sql.DriverManager.getConnection(url, username, password);
        } catch (Exception e) {
            // 捕获并打印异常信息,便于问题追踪和调试
            e.printStackTrace();
        }
        // 返回数据库连接对象
        return connection;
    }


    /**
     * 执行SQL查询语句并返回结果集
     * 此方法用于简化数据库查询操作,它封装了使用PreparedStatement执行查询的过程
     * 它通过传入的Connection对象准备SQL语句,使用参数数组填充SQL语句中的占位符,
     * 然后执行查询并返回结果集
     *
     * @param connection 数据库连接对象,用于执行SQL语句
     * @param sql SQL查询语句,可能包含占位符
     * @param preparedStatement 预编译的SQL语句对象,用于设置参数和执行查询
     * @param params 参数数组,用于填充SQL语句中的占位符
     * @param resultSet 结果集对象,用于存储查询结果
     * @return 返回执行SQL查询后得到的结果集
     * @throws SQLException 如果数据库操作失败,抛出此异常
     */
    public static ResultSet executeQuery(Connection connection, String sql,
                                          PreparedStatement preparedStatement, Object[] params,
                                          ResultSet resultSet) throws SQLException {
        // 准备SQL语句
        preparedStatement = connection.prepareStatement(sql);
        // 填充SQL语句中的占位符
        for (int i = 0; i < params.length; i++) {
            preparedStatement.setObject(i + 1, params[i]);
        }
        // 执行查询并获取结果集
        resultSet = preparedStatement.executeQuery();
        // 返回结果集
        return resultSet;
    }

    /**
     * 执行数据库更新操作
     * 该方法用于执行INSERT、UPDATE或DELETE等数据库更新操作
     * 它接受一个数据库连接、一个SQL语句、一个预编译的语句对象和一组参数作为输入
     * 参数用于填充预编译的SQL语句中的占位符
     *
     * @param connection 数据库连接对象,用于与数据库建立连接
     * @param sql 待执行的SQL语句,可能包含占位符
     * @param preparedStatement 预编译的SQL语句对象,用于执行更新操作
     * @param params 用于替换SQL语句中占位符的实际参数数组
     * @return 返回更新操作影响的行数
     * @throws SQLException 如果数据库操作失败,抛出此异常
     */
    public static int executeUpdate(Connection connection, String sql,
                                     PreparedStatement preparedStatement, Object[] params) throws SQLException {
        // 准备SQL语句:根据提供的SQL字符串和连接对象创建一个预编译的语句对象
        preparedStatement = connection.prepareStatement(sql);
        // 设置参数:遍历参数数组,将每个参数设置到预编译的语句中相应的占位符位置
        for (int i = 0; i < params.length; i++) {
            preparedStatement.setObject(i + 1, params[i]);
        }
        // 执行更新:执行预编译的SQL语句,并获取影响的行数
        // 返回结果:返回更新操作影响的行数
        return preparedStatement.executeUpdate();
    }


    /**
     * 关闭数据库连接方法
     *
     * @param connection 数据库连接对象,传入此对象以进行关闭操作
     */
    public static void closeConnection(Connection connection) {
        // 检查连接对象是否非空,以避免尝试关闭空连接导致的异常
        if (connection != null) {
            try {
                // 尝试关闭数据库连接
                connection.close();
            } catch (Exception e) {
                // 捕获并打印关闭连接时可能发生的异常,便于问题追踪和定位
                e.printStackTrace();
            }
        }
    }

    /**
     * 关闭数据库连接和声明对象
     * 此方法旨在简化资源管理,通过一次性关闭所有相关资源来防止资源泄露和潜在的内存问题
     *
     * @param conn 数据库连接对象,用于与数据库通信
     * @param preparedStatement 预编译的SQL语句对象,用于执行SQL查询或更新
     * @param resultSet 结果集对象,包含查询结果
     * @return boolean 表示是否成功关闭所有资源true表示成功,false表示过程中发生异常
     */
    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;
            }
        }
        //检查预编译的SQL语句对象是否不为空,如果不为空,则尝试关闭它
        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;
    }

}

导入基础资源

将需要用到的web相关内容导入进去,从git上找一个通用的页面模板导入,改一下请求的路径

登录功能

登录页面主要有两点功能:

  1. 已有用户登录
  2. 未有用户注册

登录页面

持久层dao层的用户登录及接口实现

与数据库交互

dao层接口

java 复制代码
package com.dashangms.dao.user;

import com.dashangms.pojo.User;

import java.sql.Connection;
import java.util.List;

public interface UserDao {

    /**
     * 用户登录查询
     *
     * @param connection   数据库连接对象
     * @param userCode     用户编码
     * @param userPassword 用户密码
     * @return 登录用户对象
     * @throws Exception 异常处理
     */
    User getLoginUser(Connection connection, String userCode, String userPassword) throws Exception;

    /**
     * 更新用户密码
     *
     * @param connection 数据库连接对象
     * @param id         用户id
     * @param newPwd     新密码
     * @return 影响行数
     * @throws Exception 异常处理
     */
    int updatePwd(Connection connection, Integer id, String newPwd) throws Exception;

    /**
     * 获取用户数量(根据用户名和角色筛选)
     *
     * @param connection    数据库连接对象
     * @param queryUserName 查询的用户名
     * @param queryUserRole 查询的角色
     * @return 用户数量
     * @throws Exception 异常处理
     */
    int getUserCount(Connection connection, String queryUserName, Integer queryUserRole) throws Exception;

    List<User> getUserList(Connection connection, String userName, int userRole,
                           int currentPageNo, int pageSize) throws Exception;

    /**
     * 根据用户id获取用户信息
     *
     * @param connection 数据库连接对象
     * @param id         用户id
     * @return 用户对象
     * @throws Exception 异常处理
     */
    User getUserById(Connection connection, int id) throws Exception;

    /**
     * 修改用户信息
     *
     * @param connection 数据库连接对象
     * @param user       用户对象
     * @return 影响行数
     * @throws Exception 异常处理
     */
    int modify(Connection connection, User user) throws Exception;

    /**
     * 根据用户id删除用户
     *
     * @param connection 数据库连接对象
     * @param delId      删除的用户id
     * @return 影响行数
     * @throws Exception 异常处理
     */
    int deleteUserById(Connection connection, Integer delId) throws Exception;

    /**
     * 添加用户
     *
     * @param connection 数据库连接对象
     * @param user       用户对象
     * @return 影响行数
     * @throws Exception 异常处理
     */
    int add(Connection connection, User user) throws Exception;

    /**
     * 检查用户编码是否存在
     *
     * @param connection 数据库连接对象
     * @param userCode   用户编码
     * @return 用户对象
     * @throws Exception 异常处理
     */
    User selectUserCodeExist(Connection connection, String userCode) throws Exception;
}

实现所需的方法

java 复制代码
package com.dashangms.dao.user;

import com.common.utils.DateUtils;
import com.dashangms.dao.BaseDao;
import com.dashangms.pojo.User;
import com.mysql.cj.util.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;

public class UserDaoImpl implements UserDao {


    // 获取一个 Logger 实例
    private static final Logger logger = LogManager.getLogger(UserDaoImpl.class);

    private final StringBuilder sb = new StringBuilder();

    /**
     * 用户登录查询
     *
     * @param connection   数据库连接对象
     * @param userCode     用户编码
     * @param userPassword 用户密码
     * @return 登录用户对象
     * @throws Exception 异常处理
     */
    @Override
    public User getLoginUser(Connection connection, String userCode, String userPassword) throws Exception {
        User user = null;
        // 检查数据库连接是否已建立
        if (connection != null) {
            PreparedStatement preparedStatement;

            // 清空StringBuilder对象
            sb.delete(0, sb.length());
            // SQL查询语句,用于验证用户登录
            sb.append("select * from smbms_user where userCode = ? and userPassword = ?");

            if (logger.isDebugEnabled()) {
                logger.debug("getLoginUser SQL: " + sb);
                logger.debug("getLoginUser params: " + userCode + " " + userPassword);
            }

            // 预编译SQL语句,提高性能和安全性
            preparedStatement = connection.prepareStatement(sb.toString());
            // 设置查询参数
            preparedStatement.setString(1, userCode);
            preparedStatement.setString(2, userPassword);
            // 执行查询
            ResultSet resultSet = preparedStatement.executeQuery();

            // Object[] params = {userCode, userPassword} ;
            // resultSet = BaseDao.executeQuery(connection, sql, preparedStatement,params,
            // resultSet);

            // 处理查询结果 resultSet != null
            if (resultSet.next()) {
                user = getUserByResult(resultSet);
            }

            // 关闭资源,避免内存泄漏
            BaseDao.closeResource(connection, preparedStatement, resultSet);
        }
        return user;
    }


    /**
     * 更新用户密码
     *
     * @param connection 数据库连接对象
     * @param id         用户id
     * @param newPwd     新密码
     * @return 影响行数
     * @throws Exception 异常处理
     */
    @Override
    public int updatePwd(Connection connection, Integer id, String newPwd) throws Exception {

        // 初始化影响行数为0
        int updateRow = 0;

        // 检查数据库连接是否为空
        if (connection != null) {
            // 预编译SQL语句以提高性能和安全性
            PreparedStatement preparedStatement;
            sb.delete(0, sb.length());
            sb.append("update smbms_user set userPassword = ? where id = ?");
            String sql = sb.toString();
            preparedStatement = connection.prepareStatement(sql);
            // 设置SQL语句参数
            preparedStatement.setString(1, newPwd);
            preparedStatement.setInt(2, id);
            // 执行更新操作并获取影响行数
            updateRow = preparedStatement.executeUpdate();
            // 关闭数据库连接和预编译语句资源
            BaseDao.closeResource(connection, preparedStatement, null);
        }

        // 返回影响行数
        return updateRow;
    }

    /**
     * 获取用户数量(根据用户名和角色筛选)
     *
     * @param connection    数据库连接对象
     * @param queryUserName 查询的用户名
     * @param queryUserRole 查询的角色
     * @return 用户数量
     * @throws Exception 异常处理
     */
    @Override
    public int getUserCount(Connection connection, String queryUserName, Integer queryUserRole) throws Exception {

        // 初始化用户数量为0
        int userCount = 0;
        // 预编译SQL语句对象
        PreparedStatement preparedStatement;
        // 结果集对象
        ResultSet resultSet;
        // 存储查询参数的列表
        ArrayList<Object> list = new ArrayList<>();

        // 检查数据库连接是否不为空
        if (connection != null) {
            sb.delete(0, sb.length());
            sb.append("select count(1) as userCount from smbms_user u, smbms_role r ")
                    .append("where u.userRole = r.id ");

            // 如果查询用户名不为空,则添加用户名模糊查询条件
            if (queryUserName != null && !queryUserName.isEmpty()) {
                sb.append(" and u.userName like ? ");
                list.add("%" + queryUserName + "%");
            }
            // 如果查询角色不为空且大于0,则添加角色精确查询条件
            if (queryUserRole != null && queryUserRole > 0) {
                sb.append("and u.userRole = ? ");
                list.add(queryUserRole);
            }

            String sql = sb.toString();
            // 准备SQL语句执行
            preparedStatement = connection.prepareStatement(sql);
            // 将查询参数列表转换为数组形式
            Object[] params = list.toArray();
            // 执行查询并获取结果集
            resultSet = BaseDao.executeQuery(connection, sql, preparedStatement, params, null);

            // 如果结果集不为空,则从结果集中获取用户数量
            if (resultSet != null && resultSet.next()) {
                userCount = resultSet.getInt("userCount");
            } else {
                // 如果结果集为空,输出提示信息
                System.out.println("用户查询不到");
            }

            // 关闭数据库资源
            BaseDao.closeResource(connection, preparedStatement, resultSet);
        }
        // 返回用户数量
        return userCount;
    }

    /**
     * 分页查询用户集合
     *
     * @param connection    数据库连接
     * @param userName      用户名字
     * @param userRole      角色id
     * @param currentPageNo 当前页码
     * @param pageSize      每页数量
     * @return 用户对象集合
     * @throws Exception 抛出SQL异常
     */
    @Override
    public List<User> getUserList(Connection connection, String userName, int userRole,
                                  int currentPageNo, int pageSize) throws Exception {
        List<User> users = new ArrayList<>();
        if (connection == null) {
            return users;
        }
        PreparedStatement preparedStatement;
        ResultSet rs;

        sb.delete(0, sb.length());

        sb.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 (!StringUtils.isNullOrEmpty(userName)) {
            sb.append(" and u.userName like ?");
            list.add("%" + userName + "%");
        }
        if (userRole > 0) {
            sb.append(" and u.userRole = ?");
            list.add(userRole);
        }
        sb.append(" order by createDate DESC limit ?, ?");

        String sql = sb.toString();
        // 准备SQL语句执行
        preparedStatement = connection.prepareStatement(sql);

        currentPageNo = (currentPageNo - 1) * pageSize;
        list.add(currentPageNo);
        list.add(pageSize);

        Object[] params = list.toArray();
        rs = BaseDao.executeQuery(connection, sql, preparedStatement, params, null);


        while (rs.next()) {
            User user = getUserByResult(rs);
//            user.setAge(user.getAge());
            user.setAge( DateUtils.getUserAge(user.getBirthday()));
            user.setUserRoleName(rs.getString("userRoleName"));

            users.add(user);
        }
        BaseDao.closeResource(connection, preparedStatement, rs);
        return users;
    }


    /**
     * 根据用户id获取用户信息
     *
     * @param connection 数据库连接对象
     * @param id         用户id
     * @return 用户对象
     * @throws Exception 异常处理
     */
    @Override
    public User getUserById(Connection connection, int id) throws Exception {
        // 预编译SQL语句对象
        PreparedStatement preparedStatement;
        // 初始化一个空的用户对象
        User user = new User();

        // 检查数据库连接是否为空
        if (connection != null) {

            sb.delete(0, sb.length());
            // SQL查询语句,根据用户id查询用户信息
            sb.append("select * from smbms_user where id = ?");

            // 准备SQL语句
            preparedStatement = connection.prepareStatement(sb.toString());
            // 设置SQL语句中的参数,即用户id
            preparedStatement.setInt(1, id);
            // 执行查询,获取结果集
            ResultSet rs = preparedStatement.executeQuery();

            if (rs != null && rs.next()) {
                // 从结果集中提取用户信息,封装到用户对象中
                user = getUserByResult(rs);
            }

            // 关闭数据库连接和资源,防止资源泄露
            BaseDao.closeResource(connection, preparedStatement, rs);
        }

        // 返回查询到的用户对象
        return user;
    }


    /**
     * 修改用户信息
     *
     * @param connection 数据库连接对象
     * @param user       用户对象
     * @return 影响行数
     * @throws Exception 异常处理
     */
    @Override
    public int modify(Connection connection, User user) throws Exception {
        PreparedStatement preparedStatement;
        int updateRows = 0;

        sb.delete(0, sb.length());

        if (connection != null) {
            sb.append("update smbms_user set ");
            sb.append(" userName = ?, ");
            sb.append(" gender = ?, ");
            sb.append(" birthday = ?, ");
            sb.append(" phone = ?, ");
            sb.append(" address = ?, ");
            sb.append(" userRole = ?, ");
            sb.append(" modifyBy = ?, ");
            sb.append(" modifyDate = ? ");
            sb.append("where id = ?");

            preparedStatement = connection.prepareStatement(sb.toString());

            Object[] params = {
                    user.getUserName(),
                    user.getGender(),
                    user.getBirthday(),
                    user.getPhone(),
                    user.getAddress(),
                    user.getUserRole(),
                    user.getModifyBy(),
                    user.getModifyDate(),
                    user.getId()
            };

            updateRows = BaseDao.executeUpdate(connection, sb.toString(), preparedStatement,
                    params);
            BaseDao.closeResource(connection, preparedStatement, null);

        }

        return updateRows;
    }

    /**
     * 根据用户id删除用户
     *
     * @param connection 数据库连接对象
     * @param delId      删除的用户id
     * @return 影响行数
     * @throws Exception 异常处理
     */
    @Override
    public int deleteUserById(Connection connection, Integer delId) throws Exception {
        PreparedStatement preparedStatement = null;
        int updateRows = 0;
        sb.delete(0, sb.length());
        if (connection != null) {
            sb.append("delete from smbms_user where id = ?");
            preparedStatement = connection.prepareStatement(sb.toString());
            preparedStatement.setInt(1, delId);
            updateRows = preparedStatement.executeUpdate();
        }
        BaseDao.closeResource(connection, preparedStatement, null);
        return updateRows;
    }

    /**
     * 添加用户
     *
     * @param connection 数据库连接对象
     * @param user       用户对象
     * @return 影响行数
     * @throws Exception 异常处理
     */
    @Override
    public int add(Connection connection, User user) throws Exception {
        PreparedStatement preparedStatement;
        int updateRows = 0;
        // 初始化StringBuilder用于拼接SQL语句
        sb.delete(0, sb.length());
        // 检查数据库连接是否有效
        if (connection != null) {
            // 构建插入用户的SQL语句
            sb.append("insert into smbms_user ( ")
                    .append(" userCode, ")
                    .append(" userName, ")
                    .append(" userPassword, ")
                    .append(" gender, ")
                    .append(" birthday, ")
                    .append(" phone, ")
                    .append(" address, ")
                    .append(" userRole, ")
                    .append(" createBy, ")
                    .append( "createDate ")
                    .append(") values (?,?,?,?,?,?,?,?,?,?)");
            // 准备SQL语句
            preparedStatement = connection.prepareStatement(sb.toString());

            // 参数
            List< Object> params = new ArrayList<>();
            params.add(user.getUserCode());
            params.add(user.getUserName());
            params.add(user.getUserPassword());
            params.add(user.getGender());
            params.add(user.getBirthday());
            params.add(user.getPhone());
            params.add(user.getAddress());
            params.add(user.getUserRole());
            params.add(user.getCreatedBy());
            params.add(user.getCreateDate());

            //执行sql 返回执行结果(成功的语句数量)
            updateRows = BaseDao.executeUpdate(connection, sb.toString(), preparedStatement,
                    params.toArray());
            //释放资源
            BaseDao.closeResource(null, preparedStatement, null);
        }
        // 返回影响的行数
        return updateRows;
    }

    /**
     * 检查用户编码是否存在
     *
     * @param connection 数据库连接对象
     * @param userCode   用户编码
     * @return 用户对象
     */
    @Override
    public User selectUserCodeExist(Connection connection, String userCode) throws Exception {
        User user = null;
        PreparedStatement preparedStatement;
        sb.delete(0, sb.length());
        if (connection != null) {
            sb.append("select * from smbms_user where userCode = ?");
            preparedStatement = connection.prepareStatement(sb.toString());
            preparedStatement.setString(1, userCode);
            ResultSet rs = preparedStatement.executeQuery();
            while (rs.next()) {
                user = getUserByResult(rs);
            }
            BaseDao.closeResource(connection, preparedStatement, null);
        }
        return user;
    }


    /**
     * 根据数据库查询结果构建User对象
     * 此方法负责从ResultSet结果集中提取用户相关字段,并将这些字段映射到User对象中
     * 它简化了从数据库结果到对象的转换过程,提高了代码的可维护性和可重用性
     *
     * @param rs 数据库查询结果集,包含构建User对象所需的所有字段信息
     * @return User 根据结果集构建的User对象,如果结果集为空,则返回null
     * @throws Exception 当从结果集提取数据时发生错误,例如字段不存在或数据类型不匹配
     */
    private User getUserByResult(ResultSet rs) throws Exception {
        User 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("createBy"));
        user.setCreateDate(rs.getTimestamp("createDate"));
        user.setModifyBy(rs.getInt("modifyBy"));
        user.setModifyDate(rs.getTimestamp("modifyDate"));

        return user;
    }
}

业务层sevice层的接口的实现

接口

java 复制代码
package com.dashangms.service.user;

import com.dashangms.pojo.User;
public interface UserService {

    /**
     * @param userCode 用户名
     * @param userPassword 密码
     * @return 用户对象
     */
    public User login(String userCode, String userPassword);
}

实现相关的业务逻辑

java 复制代码
package com.dashangms.service.user;

import com.dashangms.dao.BaseDao;
import com.dashangms.dao.user.UserDao;
import com.dashangms.dao.user.UserDaoImpl;
import com.dashangms.pojo.User;

import java.sql.Connection;
import java.sql.SQLException;

public class UserServiceImpl implements UserService{

    private final UserDao userDao ;

    public UserServiceImpl(){
        userDao = new UserDaoImpl();
    }

    /**
     * @param userCode 用户名
     * @param userPassword 密码
     * @return 用户对象
     */
    @Override
    public User login(String userCode, String userPassword) {
        Connection conn = null;
        User user = null;

        try {
            conn = BaseDao.connection();
            user = userDao.getLoginUser(conn, userCode, userPassword);
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            BaseDao.closeConnection(conn);
        }
        return user;
    }

}

编写servlet的业务逻辑

编写业务逻辑

java 复制代码
package com.dashangms.servlet;

import com.dashangms.pojo.User;
import com.dashangms.service.user.UserService;
import com.dashangms.service.user.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 {
    @Override
    protected 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("user", user);
            resp.sendRedirect(req.getContextPath() + "/jsp/frame.jsp");
        } else {
            req.setAttribute("error", " 账号或密码错误!");
            req.getRequestDispatcher("/login.jsp").forward(req, resp);
        }
    }

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

映射接口路径

xml 复制代码
    <!--注册Login servlet-->
    <servlet>
        <servlet-name>login</servlet-name>
        <servlet-class>com.dashangms.servlet.LoginServlet</servlet-class>
    </servlet>
    <!--Login servlet请求路径-->
    <servlet-mapping>
        <servlet-name>login</servlet-name>
        <url-pattern>/login</url-pattern>
    </servlet-mapping>

登出、注册、注销、修改

登出属于断开登录,操作session就可以解决

应用更改数据库的处理模式,add,delete,modify都是属于事务处理操作

登出操作的实现逻辑及方式

清楚session就可以,不再保存登录记录

java 复制代码
package com.dashangms.servlet.user;

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 {

    @Override
    public void doGet(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {

        // 移除session 中的用户信息
        request.getSession().removeAttribute("user");

        // 跳转到登录页面
        response.sendRedirect(request.getContextPath() + "/jsp/login.jsp");

    }

    Override
    public void doPost(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {

        this.doGet(request, response);

    }
}
xml 复制代码
    <!--注册Logout servlet-->
    <servlet>
        <servlet-name>logout</servlet-name>
        <servlet-class>com.dashangms.servlet.user.LogoutServlet</servlet-class>
    </servlet>
    <!--Logout servlet请求路径-->
    <servlet-mapping>
        <servlet-name>logout</servlet-name>
        <url-pattern>/logout</url-pattern>
    </servlet-mapping>

防止用户登出后可以继续访问

  1. 思路:页面登出时先走login拦截器,如果session清空就说明已退出
java 复制代码
package com.dashangms.filter;

import com.common.Constants;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class LoginFilter extends HttpFilter {

    /**
     * 执行过滤操作
     *
     * @param request  Servlet请求,用于获取HTTP请求信息
     * @param response Servlet响应,用于向客户端发送数据
     * @param chain    过滤链,用于将请求传递给下一个过滤器或目标资源
     * @throws IOException 如果在执行过程中发生I/O错误
     * @throws ServletException 如果在执行过程中发生Servlet错误
     */
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException{
        // 将ServletRequest和ServletResponse转换为HttpServletRequest和HttpServletResponse
        // 以使用它们提供的高级功能和方法
        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        HttpServletResponse httpServletResponse = (HttpServletResponse) response;

        // 检查用户会话中是否存在用户信息
        // 如果不存在,说明用户未登录或会话已过期
        if (httpServletRequest.getSession().getAttribute(Constants.USER_SESSION) == null) {
            // 重定向用户到错误页面
            // 这里假设错误页面为"/error.jsp",实际路径应根据项目具体结构设置
            httpServletResponse.sendRedirect(httpServletRequest.getContextPath() + "/error.jsp");
        } else {
            // 如果用户会话中存在用户信息,继续执行过滤链
            // 这允许请求继续传递到目标资源或下一个过滤器
            chain.doFilter(request, response);
        }

    }

    @Override
    public void init() throws ServletException {
        super.init();
    }

    @Override
    public void destroy() {
        super.destroy();
    }
}
  1. 登出后访问任意页面走过滤器处理
xml 复制代码
<!--    判断用户是否登录的过滤器-->
    <filter>
        <filter-name>LoginFilter</filter-name>
        <filter-class>com.csnz.filter.LoginFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>LoginFilter</filter-name>
        <url-pattern>/jsp/*</url-pattern>
    </filter-mapping>

修改密码功能实现

导入jsp

html 复制代码
<li><a href=${pageContext.request.contextPath}"/jsp/pwdmodify.jsp">密码修改</a></li>

实现Dao层数据接口

  1. 在Dao写一个接口
java 复制代码
int updatePwd(Connection connection, Integer id, String newPwd) throws Exception;
  1. 实现这个接口
java 复制代码
    /**
     * 更新用户密码
     *
     * @param connection 数据库连接对象
     * @param id         用户id
     * @param newPwd     新密码
     * @return 影响行数
     * @throws Exception 异常处理
     */
    @Override
    public int updatePwd(Connection connection, Integer id, String newPwd) throws Exception {

        // 初始化影响行数为0
        int updateRow = 0;

        // 检查数据库连接是否为空
        if (connection != null){
            // 预编译SQL语句以提高性能和安全性
            PreparedStatement preparedStatement = null;
            String sql = "update smbms_user set userPassword = ? where id = ?";
            preparedStatement = connection.prepareStatement(sql);
            // 设置SQL语句参数
            preparedStatement.setString(1, newPwd);
            preparedStatement.setInt(2, id);
            // 执行更新操作并获取影响行数
            updateRow = preparedStatement.executeUpdate();
            // 关闭数据库连接和预编译语句资源
            BaseDao.closeResource(connection, preparedStatement, null);
        }

        // 返回影响行数
        return updateRow;
    }

实现Service层业务接口

  1. 在Service上写一个接口
java 复制代码
    /**
     * 修改密码
     * @param id 用户id
     * @param newPwd 新密码
     * @return 修改成功 flag
     */
    public boolean updatePwd(Integer id, String newPwd);
  1. 实现这个Service
java 复制代码
    /**
     * 修改密码
     *
     * @param id     用户id
     * @param newPwd 新密码
     * @return 修改成功 flag
     */
    @Override
    public boolean updatePwd(Integer id, String newPwd) {
        Connection conn = null;
        boolean flag = false;

        try {
            conn = BaseDao.connection();
            if (userDao.updatePwd(conn, id, newPwd) > 0){
                flag = true;
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            BaseDao.closeConnection(conn);
        }

        return flag;
    }

注册Servlet

  1. 多个按钮会在同一个Servlet的中调用不同的方法;
  2. 相关密码的check逻辑:
  • 密码不能为空
  • 密码与旧密码不能相同
  • 密码输入要合法化
  1. 密码修改成功与否都会返回原页面。有msg显示。
java 复制代码
package com.dashangms.servlet.user;

import com.dashangms.pojo.User;
import com.dashangms.service.user.UserService;
import com.dashangms.service.user.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 {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String method = req.getParameter("method");
        if ("savePassword".equals(method)) {
            savePassword(req, resp);
        }
    }

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

    /**
     * 保存用户新密码
     *
     * @param req  HTTP请求对象,用于获取请求参数和进行页面转发
     * @param resp HTTP响应对象,用于进行页面转发
     * @throws ServletException 如果Servlet操作出错
     * @throws IOException      如果输入输出操作出错
     */
    private void savePassword(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        // 获取用户ID和新密码
        String id = req.getParameter("id");
        String newPwd = req.getParameter("newPwd");

        Object object = req.getSession().getAttribute("user");
        User user = (User) object;

        // 创建UserService对象
        UserService userService = new UserServiceImpl();

        if (user.getUserPassword().isEmpty()) {
            req.getSession().setAttribute("message", "密码不能为空!");

        } else if (user.getUserPassword().equals(newPwd)) {
            req.getSession().setAttribute("message", "新密码不能与旧密码相同!");

        } else {
            // 调用UserService的updatePwd方法更新用户密码
            if (userService.updatePwd(Integer.parseInt(id), newPwd)) {

                req.getSession().setAttribute("message", "密码修改成功!请使用新密码重新登陆");
                // 移除用户会话中的用户信息,表示用户已经注销
                req.getSession().removeAttribute("user");
            } else {
                // 如果密码更新失败,转发到错误页面
                req.getSession().setAttribute("message", "密码更新失败!");
            }
        }

        // 如果密码更新成功,转发到密码修改页面
        req.getRequestDispatcher("/pwdmodify.jsp").forward(req, resp);
    }
}
  1. 注册Servlet
xml 复制代码
    <servlet>
        <servlet-name>UserServlet</servlet-name>
        <servlet-class>com.dashangms.servlet.user.UserServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>UserServlet</servlet-name>
        <url-pattern>/jsp/user.do</url-pattern>
    </servlet-mapping>

注册和注销 用户的方式(优化)

同上 改善点

导入jsp

可以共同使用同一个页面,根据前面页面传的值使用hidden确定显示哪部分内容;

实现Dao层的数据逻辑

  • 插入新用户 insert
  • 注销(删除)新用户 update (逻辑删除)

实现Service逻辑

  • 插入新用户 insert
    • 使用前先判断是否有同样的账号,判断一致性插入
  • 注销(删除)新用户 update (逻辑删除)
    • 停用功能,:停用和启用相对应,不会删除数据
    • 删除功能
      • 物理删除?
      • 逻辑删除?

注册Servlet

同样在UserServlet中调用其他的逻辑,主要点 在jsp中确定实现

不需要再新注册Servlet来实现

用户管理模块

用户管理模块需要包含的功能需要有添加用户、删除用户、查询用户、修改用户;显示时会进行表单显示,有分页功能,页码计算功能。

前期准备

共同工具类

翻页使用的对象工具类,计算页数方式如下:

每次显示的页数 = 总件数 % 单页显示的件数 == 0 ? 总件数 / 单页显示的件数 :(总件数 / 单页显示的件数)+1;

java 复制代码
package com.common.utils;

public class PageSupport {

    private int pageIndex = 1; // 当前页码
    private int pageSize; // 总页数
    private int totalCount;  // 总记录数
    private int totalPageCount; // 每页显示的记录数


    public int getPageIndex() {
        return pageIndex;
    }

    public void setPageIndex(int pageIndex) {
        if (pageIndex > 0) {
            this.pageIndex = pageIndex;
        }
    }

    public int getPageSize() {
        return pageSize;
    }

    public void setPageSize(int pageSize) {
        if (pageSize > 0) {
            this.pageSize = pageSize;
        }
    }

    public int getTotalCount() {
        return totalCount;
    }

    public void setTotalCount(int totalCount) {
        if (totalCount > 0) {
            this.totalCount = totalCount;
            setByPageNo(totalCount);
        }
    }

    public int getTotalPageCount() {
        return totalPageCount;
    }

    public void setTotalPageCount(int totalPageCount) {
        this.totalPageCount = totalPageCount;
    }

    /**
     * 根据总记录数设置总页数
     * 此方法用于计算分页时的总页数,基于当前的每页记录数(pageSize)
     *
     * @param totalCount 总记录数,即需要分页处理的数据总量
     */
    private void setByPageNo(int totalCount) {
        // 计算总页数:如果总记录数除以每页记录数的余数为0,则总页数为总记录数除以每页记录数;
        // 否则,总页数为总记录数除以每页记录数加1
        this.totalPageCount = totalCount % pageSize == 0 ? totalCount / pageSize :
                totalCount / pageSize + 1;
    }

}

导入前端代码

导入前端页面和相关js,跳转页面的时候及翻页的时候使用。

获取用户数量

需要为查询数据做好基础,涉嫌到数据统计。

UserDao

通过用户名称或角色查询获取用户数量,设计的功能模块有关下拉选择查询总数。

  1. UserDao
java 复制代码
    /**
     * 获取用户数量(根据用户名和角色筛选)
     *
     * @param connection    数据库连接对象
     * @param queryUserName 查询的用户名
     * @param queryUserRole 查询的角色
     * @return 用户数量
     * @throws Exception 异常处理
     */
    int getUserCount(Connection connection, String queryUserName, Integer queryUserRole) throws Exception;
  1. UserDaoImpl
java 复制代码
    /**
     * 获取用户数量(根据用户名和角色筛选)
     *
     * @param connection    数据库连接对象
     * @param queryUserName 查询的用户名
     * @param queryUserRole 查询的角色
     * @return 用户数量
     * @throws Exception 异常处理
     */
    @Override
    public int getUserCount(Connection connection, String queryUserName, Integer queryUserRole) throws Exception {

        // 初始化用户数量为0
        int userCount = 0;
        // 预编译SQL语句对象
        PreparedStatement preparedStatement = null;
        // 结果集对象
        ResultSet resultSet = null;
        // 存储查询参数的列表
        ArrayList<Object> list = new ArrayList<>();

        // 检查数据库连接是否不为空
        if (connection != null) {

            // 构建基础SQL查询语句
            String sql = "select count(1) as userCount from smbms_user u, smbms_role r where u" +
                    ".userRole = r.id ";

            // 如果查询用户名不为空,则添加用户名模糊查询条件
            if (queryUserName != null && !queryUserName.isEmpty()) {
                sql += "and u.userName like ? ";
                list.add("%" + queryUserName + "%");
            }
            // 如果查询角色不为空且大于0,则添加角色精确查询条件
            if (queryUserRole != null && queryUserRole > 0) {
                sql += "and u.userRole = ? ";
                list.add(queryUserRole);
            }

            // 准备SQL语句执行
            preparedStatement = connection.prepareStatement(sql);
            // 将查询参数列表转换为数组形式
            Object[] params = list.toArray();
            // 执行查询并获取结果集
            resultSet = BaseDao.executeQuery(connection, sql, preparedStatement, params, resultSet);

            // 如果结果集不为空,则从结果集中获取用户数量
            if (resultSet != null) {
                userCount = resultSet.getInt("userCount");
            } else {
                // 如果结果集为空,输出提示信息
                System.out.println("用户查询不到");
            }

            // 关闭数据库资源
            BaseDao.closeResource(connection, preparedStatement, resultSet);
        }
        // 返回用户数量
        return userCount;
    }

UserService

调用Dao层的sql处理,如果出现问题及时抛出异常,之后在进行关闭连接。

  1. UserService
java 复制代码
public int getUserCount(String queryUserName, Integer queryUserRole);
  1. UserServiceImpl
java 复制代码
    /**
     * 获取用户数量
     * 根据用户名和用户角色查询用户数量
     *
     * @param queryUserName 查询的用户名,如果为null,则不根据用户名进行筛选
     * @param queryUserRole 查询的用户角色,如果为null,则不根据用户角色进行筛选
     * @return 返回查询到的用户数量
     */
    @Override
    public int getUserCount(String queryUserName, Integer queryUserRole) {
        // 定义数据库连接对象
        Connection conn = null;
        // 初始化用户数量为0
        int userCouts = 0;
        try {
            // 获取数据库连接
            conn = BaseDao.connection();
            // 调用UserDao的getUserCount方法查询用户数量
            userCouts = userDao.getUserCount(conn, queryUserName, queryUserRole);
        } catch (Exception e) {
            // 打印异常信息
            e.printStackTrace();
        } finally {
            // 关闭数据库资源
            BaseDao.closeResource(conn, null, null);
        }

        // 返回查询到的用户数量
        return userCouts;
    }

获取用户列表

根据查询条件查询需要的数据,根据翻页页数计算需要显示的数据是那些条;

UserDao

使用order by和 limit 关键字 应用;

  1. userDao
java 复制代码
List<User> getUserList(Connection connection, String userName, int userRole, int currentPageNo, int pageSize) throws Exception;
  1. userDaoImpl
java 复制代码
    /**
     * 分页查询用户集合
     * @param connection 数据库连接
     * @param userName 用户名字
     * @param userRole 角色id
     * @param currentPageNo 当前页码
     * @param pageSize 每页数量
     * @return 用户对象集合
     * @throws Exception 抛出SQL异常
     */
    @Override
    public List<User> getUserList(Connection connection, String userName, int userRole, int currentPageNo, int pageSize) throws Exception {
        List<User> users = new ArrayList<>();
        if (connection == null) {
            return users;
        }
        PreparedStatement preparedStatement = null;
        ResultSet rs = null;
        StringBuilder sql = new StringBuilder();
        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 (!StringUtils.isNullOrEmpty(userName)) {
            sql.append(" and u.userName like ?");
            list.add("%" + userName + "%");
        }
        if (userRole > 0) {
            sql.append(" and u.userRole = ?");
            list.add(userRole);
        }
        sql.append(" order by creationDate DESC limit ?, ?");

        // 准备SQL语句执行
        preparedStatement = connection.prepareStatement(sql.toString());
        
        currentPageNo = (currentPageNo - 1) * pageSize;
        list.add(currentPageNo);
        list.add(pageSize);
        Object[] params = list.toArray();
        rs = BaseDao.executeQuery(connection, sql.toString(),preparedStatement,  params, rs);
        while (rs.next()) {
            User user = getUserByResult(rs);
            user.setUserRoleName(rs.getString("userRoleName"));
            users.add(user);
        }
        BaseDao.closeResource(connection,preparedStatement, rs);
        return users;
    }

UserService

  1. UserService
java 复制代码
    List<User> getUserList(String queryUserName, int queryUserRole, int currentPageNo,
                           int pageSize);
  1. UserServiceImpl
java 复制代码
    /**
     * @param queryUserName
     * @param queryUserRole
     * @param currentPageNo
     * @param pageSize
     * @return
     */
    @Override
    public List<User> getUserList(String queryUserName, int queryUserRole, int currentPageNo,
                                  int pageSize) {

        Connection conn = null;
        List<User> userList = null;
        try {
            conn = BaseDao.connection();
            userList = userDao.getUserList(conn, queryUserName, queryUserRole, currentPageNo,
                    pageSize);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            BaseDao.closeResource(conn, null, null);
        }

        return userList;
    }

获取用户角色 列表

查询数据库中的角色

RoleDao

  1. RoleDao
java 复制代码
package com.dashangms.dao.role;

import com.dashangms.dao.BaseDao;
import com.dashangms.pojo.Role;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;

public interface RoleDao {
    List<Role> getRoleList(Connection connection) throws SQLException;
}
  1. RoleDaoImpl
java 复制代码
package com.dashangms.dao.role;

import com.dashangms.dao.BaseDao;
import com.dashangms.pojo.Role;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

public class RoleDaoImpl implements RoleDao {

    /**
     * 获取角色列表
     *
     * @param connection 数据库连接对象,用于执行SQL查询
     * @return 返回一个Role对象列表,包含从数据库查询到的所有角色信息
     * @throws SQLException 如果在执行数据库操作时发生错误
     */
    @Override
    public List<Role> getRoleList(Connection connection) throws SQLException {
        // 创建一个ArrayList用于存储Role对象
        ArrayList<Role> roleList = new ArrayList<Role>();
        // 定义ResultSet对象用于存储查询结果
        ResultSet resultSet = null;

        // 检查传入的数据库连接对象是否不为空
        if (connection != null) {
            // 定义SQL查询语句,用于从smbms_role表中查询所有数据
            String sql = "select * from smbms_role";
            // 定义一个空的参数数组,用于执行带有参数的SQL语句(此处无参数)
            Object[] params = {};

            // 执行SQL查询,并将结果存储在resultSet中
            resultSet = BaseDao.executeQuery(connection, sql, null, params, resultSet);

            // 遍历查询结果,将每条记录封装成Role对象
            while (resultSet.next()) {
                Role role = new Role();
                // 从结果集中获取id、roleCode、roleName等字段,并设置到Role对象中
                role.setId(resultSet.getInt("id"));
                role.setRoleCode(resultSet.getString("roleCode"));
                role.setRoleName(resultSet.getString("roleName"));
                role.setCreateBy(resultSet.getInt("createBy"));
                role.setCreateDate(resultSet.getTimestamp("createDate"));
                role.setModifyBy(resultSet.getInt("modifyBy"));
                role.setModifyDate(resultSet.getTimestamp("modifyDate"));
                // 将封装好的Role对象添加到列表中
                roleList.add(role);
            }

            // 关闭数据库资源,包括连接、声明和结果集
            BaseDao.closeResource(connection, null, resultSet);
        }

        // 返回角色列表
        return roleList;
    }

}

RoleService

  1. RoleService
java 复制代码
package com.dashangms.service.role;

import com.dashangms.pojo.Role;

import java.util.List;

public interface RoleService {

    List<Role> getRoleList();
}
  1. RoleServiceImpl
java 复制代码
package com.dashangms.service.role;

import com.dashangms.dao.BaseDao;
import com.dashangms.dao.role.RoleDaoImpl;
import com.dashangms.pojo.Role;
import com.dashangms.dao.role.RoleDao;

import java.sql.Connection;
import java.util.ArrayList;
import java.util.List;

public class RoleServiceImpl implements RoleService{

    private RoleDao roleDao;

    public RoleServiceImpl() {
        roleDao = new RoleDaoImpl();
    }

    /**
     */
    @Override
    public List<Role> getRoleList() {
        Connection connection = null;
        List<Role> roleList = null;
        try {
            connection = BaseDao.connection();
            roleList = roleDao.getRoleList(connection);

        }catch (Exception e){
            e.printStackTrace();
        }
        finally {
            BaseDao.closeConnection(connection);
        }
        return roleList;
    }
}

编写查询用户的Servlet

编写查询的servlet,在画面初次加载或者查询的时候调用该方法,查询数据,显示分页,避免非空场景。

doGet方法

plain 复制代码
if ("query".equals(method)) {
    query(req, resp);
}

query方法

java 复制代码
    /**
     * 处理用户查询请求的方法
     * 该方法根据用户输入的查询条件(用户名和用户角色)以及分页信息(当前页码),
     * 查询并返回用户列表同时将结果存储在HttpServletRequest对象中,
     * 以便在JSP页面中显示
     *
     * @param req 用于获取请求参数和设置属性的HttpServletRequest对象
     * @param resp 用于响应的HttpServletResponse对象
     */
    private void query(HttpServletRequest req, HttpServletResponse resp) {
        // 获取查询条件:用户名和用户角色
        String queryUserName = req.getParameter("queryUserName");
        String queryUserRoleTemp = req.getParameter("queryUserRole");
        String pageIndex = req.getParameter("pageIndex");
        int queryUserRole = 0; // 默认用户角色

        // 创建UserService实例
        UserService userService = new UserServiceImpl();
        List<User> userList;

        // 默认分页设置
        int currentPageNo = 1;
        int pageSize = 5;

        // 处理查询条件,确保空值安全
        queryUserName = queryUserName == null ? "" : queryUserName;
        queryUserRole = queryUserRoleTemp.isEmpty() ? queryUserRole :
                Integer.parseInt(queryUserRoleTemp);
        currentPageNo = pageIndex == null ? currentPageNo : Integer.parseInt(pageIndex);

        // 获取用户总数,用于分页
        int totalCount = userService.getUserCount(queryUserName, queryUserRole);

        // 创建并配置PageSupport对象
        PageSupport pageSupport = new PageSupport();
        pageSupport.setPageIndex(currentPageNo);
        pageSupport.setPageSize(pageSize);
        pageSupport.setTotalCount(totalCount);

        // 计算总页数
        int totalPageCount = pageSupport.getTotalPageCount();

        // 校验当前页码
        if (currentPageNo < 1) {
            currentPageNo = 1;
        } else {
            if (currentPageNo > totalPageCount) {
                currentPageNo = totalPageCount;
            }
        }

        // 根据查询条件和分页信息获取用户列表
        userList = userService.getUserList(queryUserName, queryUserRole, currentPageNo, pageSize);

        // 将用户列表和其他信息存储在请求对象中
        req.setAttribute("userList", userList);

        // 创建RoleService实例并获取角色列表
        RoleService roleService = new RoleServiceImpl();
        List<Role> roleList = roleService.getRoleList();

        // 将角色列表和其他信息存储在请求对象中
        req.setAttribute("roleList", roleList);
        req.setAttribute("totalCount", totalCount);
        req.setAttribute("currentPageNo", currentPageNo);
        req.setAttribute("totalPageCount", totalPageCount);
        req.setAttribute("queryUserName", queryUserName);
        req.setAttribute("queryUserRole", queryUserRole);

        // 转发到userlist.jsp页面显示结果
        try {
            req.getRequestDispatcher("/userlist.jsp").forward(req, resp);
        } catch (ServletException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

添加用户子模块

添加用户,查找用户是否存在;需要考虑到添加失败后事务回滚

导入jsp请求按钮

UserDao逻辑

  1. UserDao
java 复制代码
 //用户管理模块中的 子模块------ 添加用户
    public int addUser(Connection conn,User user)throws SQLException;
  1. UserDaoImpl
java 复制代码
 //用户管理模块中的 子模块------ 添加用户
    public  int addUser(Connection conn,User user)throws SQLException{{
        PreparedStatement preparedStatement;
        int updateRows = 0;
        if(connection != 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.getCreateDate()};

            preparedStatement = connection.prepareStatement(sql);
            //执行sql 返回执行结果(成功的语句数量)
            updateRows= BaseDao.executeUpdate(connection,sql,preparedStatement,params);
            //释放资源
            BaseDao.closeResource(null,preparedStatement,null);
        }
        return updateRows;
    }

UserService逻辑

  1. UserService
java 复制代码
//用户管理模块中的 子模块------ 添加用户
     boolean  addUser(User user);
  1. UserServiceImpl
java 复制代码
    /**
     * @param user
     * @return
     */
    @Override
    public boolean addUser(User user) throws SQLException {
        Connection conn = null;
        boolean flag = false;
        try {
            //获取数据库连接
            conn = BaseDao.connection();
            //开启JDBC事务管理
            conn.setAutoCommit(false);
            //Service层调用dao层的方法添加用户
            int updateRows = userDao.add(conn, user);
            conn.commit();
            if(updateRows > 0){
                flag = true;
            }
        } catch (Exception e) {
            e.printStackTrace();
            if (conn != null) {
                conn.rollback();
            }
        }finally {
            //释放连接
            BaseDao.closeResource(conn,null,null);
        }
        return flag;

    }

删除用户子模块

导入jsp请求按钮

UserDao逻辑

  1. UserDao
java 复制代码
    int deleteUserById(Connection connection, Integer delId) throws Exception;
  1. UserDaoImpl
java 复制代码
    /**
     * 根据用户id删除用户
     *
     * @param connection 数据库连接对象
     * @param delId      删除的用户id
     * @return 影响行数
     * @throws Exception 异常处理
     */
    @Override
    public int deleteUserById(Connection connection, Integer delId) throws Exception {
        PreparedStatement preparedStatement = null;
        int updateRows = 0;
        if(connection != null){
            String sql = "delete from smbms_user where id = ?";
            preparedStatement = connection.prepareStatement(sql);
            preparedStatement.setInt(1, delId);
            updateRows = preparedStatement.executeUpdate();
        }
        BaseDao.closeResource(connection, preparedStatement, null);
        return updateRows;
    }

UserService逻辑

  1. UserService
java 复制代码
int deleteUser(Integer delId);
  1. UserServiceImpl
java 复制代码
    /**
     * @param delId
     * @return
     */
    @Override
    public int deleteUser(Integer delId) {
        Connection conn = null;
        int delectedRows = 0;

        try {
            conn = BaseDao.connection();
            delectedRows = userDao.deleteUserById(conn, delId);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            BaseDao.closeResource(conn, null, null);
        }

        return delectedRows;
    }

修改用户子模块

导入jsp请求按钮,检查

UserDao逻辑

  1. UserDao
java 复制代码
    int modify(Connection connection, User user) throws Exception;
  1. UserDaoImpl
java 复制代码
    /**
     * 修改用户信息
     *
     * @param connection 数据库连接对象
     * @param user       用户对象
     * @return 影响行数
     * @throws Exception 异常处理
     */
    @Override
    public int modify(Connection connection, User user) throws Exception {
        PreparedStatement preparedStatement = null;
        int updateRows = 0;

        if(connection != 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()
                    };
            preparedStatement = connection.prepareStatement(sql);
            updateRows = BaseDao.executeUpdate(connection, sql, preparedStatement, params);
            BaseDao.closeResource(connection, preparedStatement, null);

        }

        return updateRows;
    }

UserService逻辑

  1. UserService
java 复制代码
int modifyUser(User user);
  1. UserServiceImp
java 复制代码
    /**
     * @param user
     * @return
     */
    @Override
    public int modifyUser(User user) {

        Connection conn = null;
        int updateRows = 0;

        try {
            conn = BaseDao.connection();
            updateRows = userDao.modify(conn, user);
            conn.commit();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            BaseDao.closeResource(conn, null, null);
        }
        return updateRows;
    }

查询用户子模块

导入jsp请求按钮,检查

思路:

  • 跟前面查询数据走同一个Dao的数据查询逻辑,在service/servlet层对数据进行区分?
  • 通过画面hidden项传递?
  • 通过页面id(主键查询)传递?

Servlet

java 复制代码
public class UserServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String method = req.getParameter("method");
        if ("savePassword".equals(method)) {
            savePassword(req, resp);
        } else if ("query".equals(method)) {
            query(req, resp);
        } else if ("modify".equals(method)) {
            modify(req, resp);
        } else if ("delete".equals(method)) {
            delete(req, resp);
        } else if ("add".equals(method)) {
            try {
                add(req, resp);
            } catch (SQLException e) {
                throw new RuntimeException(e);
            }
        } else if ("viewUser".equals(method)) {
            viewUser(req, resp);
        }
    }

/**
     * 该方法用于处理用户信息查看请求
     * 它从HTTP请求中提取用户ID,调用服务层方法获取用户信息,
     * 并将用户信息发送到前端页面进行展示
     *
     * @param req  HTTP请求对象,用于获取请求参数和设置属性
     * @param resp HTTP响应对象,用于跳转到其他页面
     * @throws ServletException 如果Servlet操作失败
     * @throws IOException      如果输入输出操作失败
     */
    private void viewUser(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //从前端获取 要查询用户 的id
        String id = req.getParameter("id");
        int userId = 0;
        try {
            //将获取到的字符串id转换为整型,以便后续使用
            userId = Integer.parseInt(id);
        } catch (Exception e) {
            //异常处理:打印错误信息,如果转换失败
            e.printStackTrace();
        }
        //调用 根据id查询用户信息的方法
        UserServiceImpl userService = new UserServiceImpl();
        User user = userService.getUserById(userId);
        //将此user发送到展示前端 的页面进行展示
        req.setAttribute("user", user);
        //跳转到前端 的展示页面
        req.getRequestDispatcher("userview.jsp").forward(req, resp);
    }
}

UserService逻辑 :getUserById

  1. UserService
java 复制代码
    User getUserById(int userId);
  1. UserServiceImpl
java 复制代码
    /**
     * @param userId
     * @return
     */
    @Override
    public User getUserById(int userId) {
        Connection conn = null;
        User user = null;

        try {
            conn = BaseDao.connection();
            user = userDao.getUserById(conn, userId);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            BaseDao.closeResource(conn, null, null);
        }
        return user;
    }

UserDao

  1. UserDao
plain 复制代码
/**
 * 根据用户id获取用户信息
 *
 * @param connection 数据库连接对象
 * @param id 用户id
 * @return 用户对象
 * @throws Exception 异常处理
 */
User getUserById(Connection connection, int id) throws Exception;
  1. UserDaoImpl :主键查询
java 复制代码
    /**
     * 根据用户id获取用户信息
     *
     * @param connection 数据库连接对象
     * @param id         用户id 主键
     * @return 用户对象
     * @throws Exception 异常处理
     */
    @Override
    public User getUserById(Connection connection, int id) throws Exception {

        PreparedStatement  preparedStatement = null;
        ResultSet rs = null;
        List<User> users =  new ArrayList<>();
        User user = new User();

        if(connection != null){
          String sql = "select * from smbms_user where id = ?";
          preparedStatement = connection.prepareStatement(sql);

//          Object[] parmes = new Object[1];
//          parmes[0] = Integer.parseInt(id);

            preparedStatement.setInt(1, id);
//          rs = BaseDao.executeQuery(connection, sql, preparedStatement, parmes, rs);
             rs = preparedStatement.executeQuery();

//          while (rs.next()){
              user = getUserByResult(rs);
//              users.add(user);
//          }

          BaseDao.closeResource(connection, preparedStatement, rs);
        }

        return user;
    }

供应商管理

前期准备

  1. 创建供应商 provider 的servlet
  2. 注册 provider 的servlet
  3. 创建相关的Dao,Service,javaBean等
  4. 导入相关的jsp

增加供应商

addProvider

PrivodeDao

  1. PrivodeDao
java 复制代码
    int addProvider(Provider provider);
  1. PrivodeDaoImpl
java 复制代码
    /**
     * 向数据库中添加供应商信息
     *
     * @param connection 数据库连接对象,用于执行SQL语句
     * @param provider   供应商对象,包含要添加的供应商的信息
     * @return 返回添加的行数,用于确认是否成功添加供应商
     * @throws Exception 如果在添加过程中发生错误,则抛出异常
     */
    @Override
    public int addProvider(Connection connection, Provider provider) throws Exception {
        // 初始化添加行数为0
        int addRows = 0;
        // 预编译的SQL语句对象
        PreparedStatement preparedStatement;

        // 检查数据库连接是否为空
        if (connection != null) {
            // 准备插入供应商信息的SQL语句
            String sql = "insert into smbms_provider (" +
                    "proCode, " +
                    "proName, " +
                    "proDesc, " +
                    "proContact, " +
                    "proPhone, " +
                    "proAddress, " +
                    "proFax, " +
                    "createBy, " +
                    "createDate) " +
                    " values(?,?,?,?,?,?,?,?,?)";
            // 初始化参数数组,用于存放SQL语句中的参数值
            Object[] params = new Object[9];
            // 设置SQL语句中的参数值
            params[0] = provider.getProCode();
            params[1] = provider.getProName();
            params[2] = provider.getProDesc();
            params[3] = provider.getProContact();
            params[4] = provider.getProPhone();
            params[5] = provider.getProAddress();
            params[6] = provider.getProFax();
            params[7] = provider.getCreateBy();
            params[8] = provider.getCreateDate();

            // 准备SQL语句执行对象
            preparedStatement = connection.prepareStatement(sql);

            // 执行插入操作,并返回添加的行数
            addRows = BaseDao.executeUpdate(connection, sql, preparedStatement, params);
        }

        // 返回添加的行数
        return addRows;
    }

ProviderService

  1. ProviderService
java 复制代码
boolean addProvider(Provider provider) throws SQLException, Exception;
  1. ProviderServiceImpl
java 复制代码
    /**
     * 添加一个新的供应商到系统中。
     * <p>
     * 此方法用于将提供的供应商对象添加到数据库中。它涉及数据库操作和事务管理,
     * 根据操作的成功或失败提交或回滚事务。
     *
     * @param provider 要添加的供应商对象,包含供应商的相关信息。
     * @return 返回一个布尔值,指示添加操作是否成功。true 表示成功,false 表示失败。
     * @throws SQLException 如果发生数据库访问错误,该方法将抛出一个 SQLException。
     */
    @Override
    public boolean addProvider(Provider provider) throws SQLException {
        // 初始化数据库连接对象和方法返回值
        Connection conn = null;
        boolean flag = false;

        try {
            // 获取数据库连接并准备事务
            conn = BaseDao.connection();
            conn.setAutoCommit(false);

            // 调用数据访问对象方法添加供应商,并尝试提交事务
            int addRows = providerDao.addProvider(conn, provider);
            conn.commit();

            // 根据受影响的行数判断添加是否成功
            if (addRows > 0) {
                flag = true;
            }

        } catch (SQLException e) {
            // 遇到 SQLException 时回滚事务
            conn.rollback();
        } catch (Exception e) {
            // 对于其他异常,转换为 RuntimeException 并重新抛出
            throw new RuntimeException(e);
        } finally {
            // 在 finally 块中关闭数据库资源以确保执行
            BaseDao.closeResource(conn, null, null);
        }

        // 返回添加供应商的结果
        return flag;
    }

ProviderServlet

java 复制代码
   /**
     * 处理HTTP Post请求的方法
     * 根据请求参数中的method字段值,决定执行相应的操作
     *
     * @param req  HttpServletRequest对象,用于获取请求参数
     * @param resp HttpServletResponse对象,用于向客户端发送数据
     * @throws ServletException 如果Servlet操作失败
     * @throws IOException      如果发生输入输出异常
     */
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 获取请求参数中的method值,如果为空则默认为空字符串
        String method = req.getParameter("method") == null ? "" : req.getParameter("method");
        
        // 根据method值调用对应的方法执行操作
        switch (method) {
            case "add":
                addProvider(req, resp);
                break;
        }
    }



    /**
     * 添加供应商信息
     * <p>
     * 此方法从HTTP请求中提取供应商信息,并将其添加到数据库中
     * 如果添加成功,将用户重定向到供应商查询页面;如果添加失败,则重定向回添加供应商页面,并显示错误信息
     *
     * @param req  HTTP请求对象,用于获取请求参数和会话信息
     * @param resp HTTP响应对象,用于重定向用户
     * @throws ServletException 如果Servlet操作失败
     * @throws IOException      如果输入/输出操作失败
     */
    private void addProvider(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        // 获取当前登录用户信息
        User user = (User) req.getSession().getAttribute(Constants.USER_SESSION);

        // 创建一个新的供应商对象,并从请求中设置其属性
        Provider provider = new Provider();
        provider.setProCode(req.getParameter("proCode"));
        provider.setProName(req.getParameter("proName"));
        provider.setProDesc(req.getParameter("proDesc"));
        provider.setProContact(req.getParameter("proContact"));
        provider.setProPhone(req.getParameter("proPhone"));
        provider.setProAddress(req.getParameter("proAddress"));
        provider.setProFax(req.getParameter("proFax"));
        // 设置创建者和修改者为当前用户
        provider.setCreateBy(user.getId());
        provider.setModifyBy(user.getId());
        // 设置创建和修改日期为当前日期
        provider.setCreateDate(new Date());
        provider.setModifyDate(new Date());

        // 尝试将供应商信息添加到数据库中
        try {
            if (providerService.addProvider(provider)) {
                // 如果添加成功,设置成功消息并重定向到供应商查询页面
                req.getSession().setAttribute("message", "添加成功!");
                resp.sendRedirect(req.getContextPath() + "/provider?method=query");
            } else {
                // 如果添加失败,设置错误消息并重定向回添加供应商页面
                req.getSession().setAttribute("message", "添加失败!");
                resp.sendRedirect(req.getContextPath() + "/jsp/provideradd.jsp");
            }
        } catch (Exception e) {
            // 如果发生异常,抛出运行时异常
            throw new RuntimeException(e);
        }

        // 无论上述操作结果如何,最终将用户重定向回添加供应商页面
//        req.getRequestDispatcher("/jsp/provideradd.jsp").forward(req, resp);
    }

删除供应商

deleteProvider

ProviderDao

  1. ProviderDao
java 复制代码
int deleteProvider(Connection connection, int id) throws SQLException;
  1. ProviderDaoImpl
java 复制代码
    /**
     * 根据给定的ID删除供应商信息
     *
     * @param connection 数据库连接对象,用于执行SQL语句
     * @param id         需要删除的供应商的ID
     * @return 返回删除的行数,表示删除成功的记录数
     * @throws SQLException 如果执行SQL语句时发生错误
     */
    @Override
    public int deleteProvider(Connection connection, int id) throws SQLException {

        int deleteRows = 0;
        PreparedStatement preparedStatement;

        if (connection != null) {
            // 定义删除供应商的SQL语句
            String sql = "delete from smbms_provider where id=?";
            // 准备SQL语句
            preparedStatement = connection.prepareStatement(sql);
            // 设置SQL语句中的参数
            preparedStatement.setInt(1, id);
            // 执行更新操作
            deleteRows = preparedStatement.executeUpdate();
            // 关闭资源
            BaseDao.closeResource(connection, preparedStatement, null);
        }

        // 返回删除的行数
        return deleteRows;
    }

ProviderService

  1. ProviderService
java 复制代码
void deleteProvider(int id);
  1. ProviderServiceImpl
java 复制代码
/**
 * 根据供应商ID删除供应商信息
 * 
 * @param id 供应商的ID,用于标识要删除的供应商
 * @return 返回删除的行数,用于确认是否成功删除供应商信息
 */
@Override
public int deleteProvider(int id) {
    // 初始化删除行数为0
    int deleteRows = 0;
    // 声明数据库连接对象
    Connection conn = null;
    try {
        // 获取数据库连接
        conn = BaseDao.connection();
        // 调用供应商数据访问对象的删除方法,执行删除操作
        deleteRows = providerDao.deleteProvider(conn, id);
    } catch (SQLException e) {
        // 如果捕获到SQL异常,抛出运行时异常
        throw new RuntimeException(e);
    } finally {
        // 关闭数据库资源,确保数据库连接被释放
        BaseDao.closeResource(conn, null, null);
    }
    // 返回删除的行数
    return deleteRows;
}

ProviderServlet

java 复制代码
   /**
     * 处理HTTP Post请求的方法
     * 根据请求参数中的method字段值,决定执行相应的操作
     *
     * @param req  HttpServletRequest对象,用于获取请求参数
     * @param resp HttpServletResponse对象,用于向客户端发送数据
     * @throws ServletException 如果Servlet操作失败
     * @throws IOException      如果发生输入输出异常
     */
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 获取请求参数中的method值,如果为空则默认为空字符串
        String method = req.getParameter("method") == null ? "" : req.getParameter("method");
        
        // 根据method值调用对应的方法执行操作
        switch (method) {
            case "add":
                addProvider(req, resp);
                break;
            case "deleteProvider":
                deleteProvider(req, resp);
                break;
        }
    }

更改供应商信息

modifyProvider

ProviderDao

  1. ProviderDao
java 复制代码
int updateProvider(Connection connection, Provider provider) throws SQLException;
  1. ProviderDaoImpl
java 复制代码
    /**
     * 更新供应商信息
     *
     * @param connection 数据库连接对象,用于执行SQL语句
     * @param provider   待更新的供应商对象,包含新的供应商信息
     * @return 返回更新影响的行数,用于判断更新操作是否成功
     * @throws SQLException 如果执行SQL语句时发生错误
     */
    @Override
    public int updateProvider(Connection connection, Provider provider) throws SQLException {
        int upRows = 0;
        PreparedStatement preparedStatement;

        // 检查数据库连接是否非空,确保可以安全地执行SQL语句
        if (connection != null) {
            // 准备更新供应商信息的SQL语句
            String sql = "update smbms_provider set " +
                    "proCode=?, " +
                    "proName=?, " +
                    "proDesc=?, " +
                    "proContact=?, " +
                    "proPhone=?, " +
                    "proAddress=?, " +
                    "proFax=?, " +
                    "modifyBy=?, " +
                    "modifyDate=? " +
                    "where id=?";
            // 初始化参数数组,用于存储供应商信息
            Object[] params = new Object[9];
            params[0] = provider.getProCode();
            params[1] = provider.getProName();
            params[2] = provider.getProDesc();
            params[3] = provider.getProContact();
            params[4] = provider.getProPhone();
            params[5] = provider.getProAddress();
            params[6] = provider.getProFax();
            params[7] = provider.getModifyBy();
            params[8] = provider.getModifyDate();
            // 准备SQL语句执行对象
            preparedStatement = connection.prepareStatement(sql);
            // 执行更新操作并获取影响的行数
            upRows = BaseDao.executeUpdate(connection, sql, preparedStatement, params);
            // 关闭资源,避免内存泄漏
            BaseDao.closeResource(connection, preparedStatement, null);
        }

        // 返回更新影响的行数
        return upRows;
    }

ProviderService

  1. ProviderService
java 复制代码
int updateProvider(Provider provider) throws SQLException;
  1. ProviderServiceImpl
java 复制代码
    /**
     * 更新供应商信息
     * <p>
     * 此方法用于更新数据库中供应商的信息它接收一个Provider对象作为参数,
     * 该对象包含了需要更新的供应商的新信息方法通过调用providerDao的updateProvider
     * 方法来执行数据库更新操作如果更新过程中遇到异常,会进行回滚操作以确保数据一致性
     *
     * @param provider 包含了需要更新的供应商信息的Provider对象
     * @return 返回更新影响的行数,用于判断更新操作是否成功
     * @throws SQLException 如果数据库操作失败,抛出此异常
     */
    @Override
    public int updateProvider(Provider provider) throws SQLException {
        int upRows = 0;
        Connection conn = null;
        try {
            // 获取数据库连接
            conn = BaseDao.connection();
            // 执行更新操作
            upRows = providerDao.updateProvider(conn, provider);
        } catch (SQLException e) {
            // 更新失败时,进行事务回滚
            conn.rollback();
        } finally {
            // 关闭数据库资源
            BaseDao.closeResource(conn, null, null);
        }

        return upRows;
    }

ProviderServlet

java 复制代码
   /**
     * 处理HTTP Post请求的方法
     * 根据请求参数中的method字段值,决定执行相应的操作
     *
     * @param req  HttpServletRequest对象,用于获取请求参数
     * @param resp HttpServletResponse对象,用于向客户端发送数据
     * @throws ServletException 如果Servlet操作失败
     * @throws IOException      如果发生输入输出异常
     */
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 获取请求参数中的method值,如果为空则默认为空字符串
        String method = req.getParameter("method") == null ? "" : req.getParameter("method");
        
        // 根据method值调用对应的方法执行操作
        switch (method) {
            case "modify":
                modifyProvider(req, resp);
                break;
        }
    }

    /**
     * 更新一条记录
     *
     * @param req  用于获取请求信息和会话对象
     * @param resp 用于向客户端发送响应
     */
    private void modifyProvider(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 获取当前登录用户信息
        User user = (User) req.getSession().getAttribute(Constants.USER_SESSION);

        // 创建Provider对象,并从请求中获取参数来设置对象属性
        Provider provider = new Provider();
        provider.setId(Integer.parseInt(req.getParameter("id")));
        provider.setProName(req.getParameter("proName"));
        provider.setProCode(req.getParameter("proCode"));
        provider.setProDesc(req.getParameter("proDesc"));
        provider.setProContact(req.getParameter("proContact"));
        provider.setProPhone(req.getParameter("proPhone"));
        provider.setProAddress(req.getParameter("proAddress"));
        provider.setProFax(req.getParameter("proFax"));
        // 设置修改者为当前登录用户
        provider.setModifyBy(user.getId());
        // 设置修改时间为当前时间
        provider.setModifyDate(new Date());

        try {
            // 尝试更新数据库中的Provider记录
            if (providerService.updateProvider(provider) > 0) {
                // 如果更新成功,设置会话消息
                req.getSession().setAttribute("message", "数据更新成功!");
            } else {
                // 如果更新失败,设置会话消息
                req.getSession().setAttribute("message", "数据更新失败!");
            }
        } catch (SQLException e) {
            // 如果捕获到SQLException,则抛出运行时异常
            throw new RuntimeException(e);
        }

        // 跳转到列表页面
        req.getRequestDispatcher("/provider?method=view").forward(req, resp);
    }

查询供应商信息

需要两个方法

  1. getProviderCounts、
  2. getProviderList

ProviderDao

  1. ProviderDao
java 复制代码
   public List<Provider> getProviderList(Connection connection, String proName, String proCode) throws Exception;
  1. ProviderDaoImpl
java 复制代码
    /**
     * 根据供应商名称和编码获取供应商列表
     *
     * @param connection 数据库连接对象,用于执行数据库操作
     * @param proName    供应商名称,用于筛选供应商列表
     * @param proCode    供应商编码,用于筛选供应商列表
     * @return 返回一个包含符合条件的供应商对象的列表
     * @throws Exception 如果数据库操作失败,抛出异常
     */
    @Override
    public List<Provider> getProviderList(Connection connection, String proName, String proCode) throws Exception {

        List<Provider> providers = new ArrayList<Provider>();
        Provider provider = new Provider();
        PreparedStatement preparedStatement;
        ResultSet resultSet = null;
        String sql = "select * from smbms_provider ";
        // 初始化参数列表,用于存储查询条件参数
        List<Object> list = new ArrayList<Object>();

        if (connection != null) {
            // 构建SQL查询语句
            sql += "where 1=1";
            // 如果供应商名称不为空,添加供应商名称模糊查询条件
            if (!proName.isEmpty()) {
                sql += "and proName like ? ";
                list.add("%" + proName + "%");
            }
            // 如果供应商编码不为空,添加供应商编码模糊查询条件
            if (!proCode.isEmpty()) {
                sql += "and proCode = ? ";
                list.add( proCode );
            }

            // 准备SQL语句执行对象
            preparedStatement = connection.prepareStatement(sql);

            // 执行查询并获取结果集
            resultSet = BaseDao.executeQuery(connection, sql, preparedStatement, list.toArray(),
                    resultSet);

            // 遍历结果集,将每条记录转换为供应商对象,并添加到列表中
            while (resultSet.next()) {
                providers.add(getProviderByResult(resultSet));
            }

            // 关闭数据库资源
            BaseDao.closeResource(connection, preparedStatement, resultSet);
        }

        // 返回供应商列表
        return providers;
    }

ProviderService

  1. ProviderService
java 复制代码
    List<Provider> getProviderList(String proName, String proCode);
  1. ProviderServiceImpl
java 复制代码
    /**
     * 根据供应商名称和编码获取供应商列表
     *
     * @param proName 供应商名称,用于模糊查询
     * @param proCode 供应商编码,用于精确查询
     * @return 返回一个包含查询结果的供应商列表如果查询结果为空,则返回一个空列表
     */
    @Override
    public List<Provider> getProviderList(String proName, String proCode) {

        // 初始化供应商列表
        List<Provider> providers = new ArrayList<>();
        // 获取数据库连接
        Connection conn = BaseDao.connection();

        try {
            // 调用Dao层方法,根据供应商名称和编码查询供应商列表
            providers = providerDao.getProviderList(conn, proName, proCode);
        } catch (Exception e) {
            // 异常处理:打印异常信息
            e.printStackTrace();
        } finally {
            // 关闭数据库连接
            BaseDao.closeConnection(conn);
        }

        // 返回查询到的供应商列表
        return providers;
    }

ProviderServlet

java 复制代码
   /**
     * 处理HTTP Post请求的方法
     * 根据请求参数中的method字段值,决定执行相应的操作
     *
     * @param req  HttpServletRequest对象,用于获取请求参数
     * @param resp HttpServletResponse对象,用于向客户端发送数据
     * @throws ServletException 如果Servlet操作失败
     * @throws IOException      如果发生输入输出异常
     */
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        // 获取请求参数中的method值,如果为空则默认为空字符串
        String method = req.getParameter("method") == null ? "" : req.getParameter("method");
        
        // 根据method值调用对应的方法执行操作
        switch (method) {
            case "modify":
                modifyProvider(req, resp);
                break;
        }
    }

    /**
     * 获取多条记录
     *
     * @param req  用于从HTTP请求中获取参数和设置属性
     * @param resp 用于发送HTTP响应
     */
    private void getProviderList(HttpServletRequest req, HttpServletResponse resp) {
        // 从请求中获取查询参数
        String queryProCode = req.getParameter("queryProCode");
        String queryProName = req.getParameter("queryProName");
        // 对查询参数进行空值检查并赋予默认值
        queryProCode = queryProCode == null ? "" : queryProCode;
        queryProName = queryProName == null ? "" : queryProName;

        // 调用服务层方法获取供应商列表
        List<Provider> providerList = providerService.getProviderList(queryProCode, queryProName);

        try {
            if (providerList != null) {
                // 如果列表不为空,设置请求属性并转发到供应商列表页面
                req.setAttribute("providerList", providerList);
                req.getRequestDispatcher("/providerlist.jsp");
            } else {
                // 如果列表为空,重定向到供应商查询页面
                resp.sendRedirect(req.getContextPath() + "/provider?method=query");
            }
        } catch (Exception e) {
            // 异常处理: 打印异常信息
            e.printStackTrace();
        }
    }

订单管理

前期准备

  1. 创建供应商 、bill 的servlet
  2. 注册 bill 的servlet
  3. 创建相关的Dao,Service,javaBean等
  4. 导入相关的jsp

新增订单

billDao

  1. billDao
java 复制代码
    boolean addBill(Connection connection, Bill bill) throws SQLException;
  1. billDaoImpl
java 复制代码
    /**
     * @param connection 数据库连接对象
     * @param bill       订单对象
     * @return 添加结果
     */
    @Override
    public boolean addBill(Connection connection, Bill bill) throws SQLException {

        boolean addFlag = false;
        int addRows;

        PreparedStatement preparedStatement;
        String sql = "insert into smbms_bill values (null,?,?,?,?,?,?,?,?,?,?,?,?)";

        preparedStatement = connection.prepareStatement(sql);

        Object[] params = {
                bill.getBillCode(),
                bill.getProductName(),
                bill.getProductDesc(),
                bill.getProductUnit(),
                bill.getProductCount(),
                bill.getTotalPrice(),
                bill.getIsPayment(),
                bill.getCreatedBy(),
                bill.getCreationDate(),
                bill.getModifyBy(),
                bill.getModifyDate(),
                bill.getProviderId()
        };

        addRows = BaseDao.executeUpdate(connection, sql, preparedStatement, params);

        if (addRows > 0) {
            addFlag = true;
        }

        BaseDao.closeResource(connection, preparedStatement, null);

        return addFlag;
    }
s

billService

  1. billService
java 复制代码
    boolean addBill(Bill bill) throws SQLException;
  1. billServiceImpl
java 复制代码
    /**
     * 添加账单到数据库
     * <p>
     * 此方法负责将一个账单对象添加到数据库中它首先获取一个数据库连接,
     * 然后尝试使用账单DAO的addBill方法将账单添加到数据库中
     * 如果在添加过程中遇到SQLException,将抛出RuntimeException
     * 最后,无论添加是否成功,都会关闭数据库资源
     *
     * @param bill 要添加到数据库的账单对象,包含账单的所有必要信息
     * @return boolean 表示账单是否成功添加到数据库中当前方法中此参数未被使用
     */
    @Override
    public boolean addBill(Bill bill) throws SQLException {

        Connection conn = null;
        boolean addFlag = false;

        try {
            // 获取数据库连接
            conn = BaseDao.connection();
            conn.setAutoCommit(false);
            // 调用账单DAO的添加方法,执行账单添加操作
            addFlag = billDao.addBill(conn, bill);
            conn.commit();
        } catch (Exception e) {
            e.printStackTrace();
            conn.rollback();
        } finally {
            // 关闭数据库资源,确保连接被释放回连接池
            BaseDao.closeResource(conn, null, null);
        }

        return addFlag;
    }

billServlet

  1. billServlet
java 复制代码
    /**
     * 获取账单列表
     * <p>
     * 此方法负责处理账单查询请求,根据不同的查询条件(如产品名称、供应商ID、是否已支付),
     * 从数据库中获取相应的账单信息,并进行分页处理,最后将结果展示在页面上
     *
     * @param req  用于获取请求参数和设置请求属性
     * @param resp 用于实现请求转发或重定向
     * @throws ServletException 如果Servlet操作失败
     * @throws IOException      如果输入输出操作失败
     */
    private void getBill(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        // 默认值初始化
        String productName = "";
        int isPayment = 0;
        int providerId = 0;

        // 获取request参数
        String queryProductName = req.getParameter("queryProductName");
        String queryProviderId = req.getParameter("queryProviderId");
        String queryIsPayment = req.getParameter("queryIsPayment");
        String pageIndex = req.getParameter("pageIndex");

        // 默认分页设置
        int currentPageNo = 1;
        int pageSize = 5;

        // TODO: 处理查询条件,确保空值安全,isPayment、providerId --> int
        queryProductName = queryProductName == null ? "" : queryProductName;
        queryProviderId = queryProviderId == null ? "" : queryProviderId;
        queryIsPayment = queryIsPayment == null ? "" : queryIsPayment;
        currentPageNo = pageIndex == null ? currentPageNo : Integer.parseInt(pageIndex);

        // 创建BillService实例
        BillService billService = new BillServiceImpl();

        // 获取账单总数
        int totalCount = billService.getBillCount(queryProductName, queryProviderId,
                queryIsPayment);

        // 创建PageSupport实例用于分页处理
        PageSupport pageSupport = new PageSupport();

        // 设置分页参数
        pageSupport.setTotalCount(totalCount);
        pageSupport.setPageIndex(currentPageNo);
        pageSupport.setPageSize(pageSize);

        // 计算总页数
        int totalPageCount = pageSupport.getTotalPageCount();

        // 校验当前页码
        if (currentPageNo < 1) {
            currentPageNo = 1;
        } else if (currentPageNo > totalPageCount) {
            currentPageNo = totalPageCount;
        }

        // 获取账单列表
        List<Bill> billList = billService.getBillList(queryProductName, queryProviderId,
                queryIsPayment);

        // 处理完的数据存到request中,用于页面展示
        req.setAttribute("billList", billList);
        req.setAttribute("queryProductName", queryProductName);
        req.setAttribute("queryProviderId", queryProviderId);
        req.setAttribute("queryIsPayment", queryIsPayment);

        req.setAttribute("totalPageCount", totalPageCount);
        req.setAttribute("totalCount", totalCount);
        req.setAttribute("currentPageNo", currentPageNo);

        // 跳转到list页面
        req.getRequestDispatcher("/billlist.jsp").forward(req, resp);

    }
  1. web.xml
java 复制代码
    <servlet>
        <servlet-name>BillServlet</servlet-name>
        <servlet-class>com.dashangms.servlet.bill.BillServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>BillServlet</servlet-name>
        <url-pattern>/jsp/bill.do</url-pattern>
    </servlet-mapping>
    <servlet-mapping>
        <servlet-name>BillServlet</servlet-name>
        <url-pattern>/bill</url-pattern>
    </servlet-mapping>

jsp

html 复制代码
<a href="${pageContext.request.contextPath}/jsp/billadd.jsp">添加订单</a>

取消订单

billDao

  1. billDao
java 复制代码
int deleteBill(Connection connection, int delId) throws SQLException;
  1. billDaoImpl
java 复制代码
/**
 * 根据给定的数据库连接和ID删除账单记录
 *
 * @param connection 数据库连接对象,用于执行SQL语句
 * @param delId      要删除的账单的ID
 * @return 返回删除的行数,表示删除成功的记录数
 * @throws SQLException 如果执行SQL语句时发生错误
 */
@Override
public int deleteBill(Connection connection, int delId) throws SQLException {

    // 初始化删除的行数为0
    int deletedRows = 0;
    // 初始化PreparedStatement对象为null,用于执行SQL语句
    PreparedStatement preparedStatement = null;

    // 检查数据库连接是否不为null
    if (connection != null) {
        // 定义SQL语句,用于删除指定ID的账单记录
        String sql = "delete from smbms_bill where id=?";
        // 准备SQL语句
        preparedStatement = connection.prepareStatement(sql);

        // 创建一个包含要删除账单ID的参数数组
        Object[] param = {delId};

        // 执行更新操作并获取删除的行数
        deletedRows = BaseDao.executeUpdate(connection, sql, preparedStatement, param);
    }
    // 关闭数据库资源
    BaseDao.closeResource(connection, preparedStatement, null);

    // 返回删除的行数
    return deletedRows;
}

billService

  1. billService
java 复制代码
    boolean deleteBill(String delId) throws SQLException;
  1. billServiceImpl
java 复制代码
    /**
     * 根据ID删除账单
     *
     * @param delId 要删除的账单的ID
     * @return 如果删除成功,返回true;否则返回false
     * @throws SQLException 如果与数据库交互时发生错误,抛出此异常
     */
    @Override
    public boolean deleteBill(String delId) throws SQLException {

        // 初始化删除标志为false
        boolean deleteFlag = false;

        int delIdTmp = Integer.parseInt(delId != null ? delId : "0");

        // 定义数据库连接对象
        Connection conn = null;
        try {
            // 获取数据库连接
            conn = BaseDao.connection();
            // 设置手动管理事务
            conn.setAutoCommit(false);

            // 调用Dao层方法,执行删除操作
            int deleteRows = billDao.deleteBill(conn, delIdTmp);

            // 检查删除的行数,如果大于0,表示删除成功
            if (deleteRows > 0) {
                deleteFlag = true;
            }
            // 提交事务
            conn.commit();

        } catch (SQLException e) {
            // 打印异常信息
            e.printStackTrace();
            // 回滚事务
            conn.rollback();

        } finally {
            // 关闭数据库资源
            BaseDao.closeResource(conn, null, null);
        }

        // 返回删除标志
        return deleteFlag;
    }

billServlet

  1. billServlet
java 复制代码
    /**
     * 删除账单操作
     *
     * 此方法用于处理从 HttpServletRequest 请求中获取的删除账单指令
     * 它调用 BillService 接口的实现来执行实际的删除操作,并根据删除结果
     * 设置 session 属性以提供反馈信息,然后重定向到账单查询页面
     *
     * @param req 用于获取删除指令的 HTTP 请求对象
     * @param resp 用于重定向到查询页面的 HTTP 响应对象
     * @throws ServletException 如果 Servlet 操作失败
     * @throws IOException 如果输入/输出操作失败
     * @throws SQLException 如果与数据库的交互操作失败
     */
    private void delBill(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException, SQLException {
        // 实例化 BillService 的实现类
        BillService billService = new BillServiceImpl();

        // 根据删除结果设置 session 属性和重定向消息
        if (billService.deleteBill(req.getParameter("delId"))) {
            req.getSession().setAttribute("message", "删除成功!");
        } else {
            req.getSession().setAttribute("message", "删除失败!");
        }
        // 重定向到账单查询页面
        resp.sendRedirect(req.getContextPath() + "/provider?method=query");
        // TODO: 前端使用ajax传递数据,需要转换为json格式
    }
  1. web.xml

jsp

html 复制代码
<span><a class="deleteBill" href="javascript:;" billid=${bill.id} billcc=${bill.billCode}><img src="${pageContext.request.contextPath}/images/schu.png" alt="删除" title="删除"/></a></span>

更改订单信息

billDao

  1. billDao
java 复制代码
int updateBill(Connection connection, Bill bill) throws SQLException;
  1. billDaoImpl
java 复制代码
    /**
     * 更新账单信息
     *
     * @param connection 数据库连接对象,用于执行SQL语句
     * @param bill 账单对象,包含需要更新的账单信息
     * @return 返回受影响的行数,用于判断更新操作是否成功
     * @throws SQLException 如果执行SQL语句时发生错误,抛出此异常
     */
    @Override
    public int updateBill(Connection connection, Bill bill) throws SQLException {
        int updateRows = 0;

        PreparedStatement preparedStatement = null;

        // 定义更新账单信息的SQL语句
        String sql = "update smbms_bill set " +
                "billCode=?," +
                "productName=?, " +
                "productDesc=?," +
                "productUnit=?," +
                "productCount=?," +
                "totalPrice=?," +
                "isPayment=?," +
                "modifyBy=?," +
                "modifyDate=?," +
                "providerId=?" +
                "where id=?";

        // 准备SQL语句参数,按照顺序从bill对象中获取属性值
        Object[] params = {
                bill.getBillCode(),
                bill.getProductName(),
                bill.getProductDesc(),
                bill.getProductUnit(),
                bill.getProductCount(),
                bill.getTotalPrice(),
                bill.getIsPayment(),
                bill.getModifyBy(),
                bill.getModifyDate(),
                bill.getProviderId(),
                bill.getId()
        };

        // 执行更新操作并获取受影响的行数
        updateRows = BaseDao.executeUpdate(connection, sql, preparedStatement, params);

        // 关闭数据库连接
        BaseDao.closeConnection(connection);

        // 返回受影响的行数
        return updateRows;
    }

billService

  1. billService
java 复制代码
boolean updateBill(Bill bill) throws SQLException;
  1. billServiceImpl
java 复制代码
    /**
     * 更新账单信息
     *
     * @param bill 要更新的账单对象,包含账单的详细信息
     * @return 返回一个布尔值,表示账单信息是否更新成功
     * @throws SQLException 如果数据库操作失败,抛出SQLException
     */
    @Override
    public boolean updateBill(Bill bill) throws SQLException {
        // 初始化更新标志为false,用于表示账单信息是否更新成功
        boolean updateFlag = false;
        // 初始化更新行数为0,用于记录数据库中受影响的行数
        int updateRows = 0;
        // 声明数据库连接对象
        Connection conn = null;

        // 获取数据库连接updateBill
        try {
            // 获取数据库连接
            conn = BaseDao.connection();
            // 设置连接为手动管理事务
            conn.setAutoCommit(false);
            // 调用BillDao的updateBill方法更新账单信息
            updateRows = billDao.updateBill(conn, bill);
            // 提交事务
            conn.commit();
            // 如果更新行数大于0,表示账单信息更新成功
            if (updateRows > 0) {
                updateFlag = true;
            }
        } catch (Exception e) {
            // 打印异常信息
            e.printStackTrace();
            // 回滚事务
            conn.rollback();
        } finally {
            // 关闭数据库资源
            BaseDao.closeResource(conn, null, null);
        }

        // 返回更新标志
        return updateFlag;
    }

billServlet

  1. billServlet
java 复制代码
    /**
     * 更新账单信息
     * 
     * @param req 用于获取请求参数和会话信息
     * @param resp 用于重定向页面
     * @throws ServletException 如果Servlet操作失败
     * @throws IOException 如果输入/输出操作失败
     * @throws SQLException 如果数据库操作失败
     */
    private void updateBill(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException, SQLException {
        // 实例化BillService接口和Bill类
        BillService billService = new BillServiceImpl();
        Bill bill = new Bill();
    
        // 从请求参数中设置账单属性
        bill.setBillCode(req.getParameter("billCode"));
        bill.setProductName(req.getParameter("productName"));
        bill.setProductDesc(req.getParameter("productDesc"));
        bill.setProductUnit(new BigDecimal(req.getParameter("productUnit")));
        bill.setProductCount(new BigDecimal(req.getParameter("productCount")));
        bill.setTotalPrice(req.getParameter("totalPrice"));
        bill.setIsPayment(Integer.parseInt(req.getParameter("isPayment")));
        bill.setProviderId(Integer.parseInt(req.getParameter("providerId")));
        bill.setId(Integer.parseInt(req.getParameter("id")));
        bill.setModifyBy(Integer.parseInt(req.getParameter("userId")));
        bill.setModifyDate(new Date());
    
        // 根据账单服务的更新结果决定重定向的页面和会话消息
        if (billService.updateBill(bill)) {
            req.getSession().setAttribute("message", "修改成功!");
            resp.sendRedirect(req.getContextPath() + "/provider?method=query");
        } else {
            req.getSession().setAttribute("message", "修改失败!");
            resp.sendRedirect(req.getContextPath() + "/provider?method=modify");
        }
    }
  1. web.xml

jsp

查询订单信息

billDao

  1. billDao
java 复制代码
    List<Bill> queryBillBy(Connection connection, String queryProductName, String queryProviderId, String queryIsPayment ) throws SQLException;
  1. billDaoImpl
java 复制代码
    /**
     * 查询订单详情
     * 根据请求过来的信息查询内容,返回结果,内容为空的时候显示所有订单
     *
     * @param connection       数据库连接对象
     * @param queryProductName 商品名称
     * @param queryProviderId  商品id
     * @param queryIsPayment   是否付款
     * @return 订单列表
     */
    @Override
    public List<Bill> queryBillBy(Connection connection, String queryProductName,
                                  String queryProviderId, String queryIsPayment) throws SQLException {
        ResultSet resultSet = null;
        List<Bill> billList = new ArrayList<>();
        List<Object> params = new ArrayList<>();

        PreparedStatement preparedStatement;
        String sql = "select * from smbms_bill ";

        if (queryProductName != null || queryProviderId != null || queryIsPayment != null) {
            sql += "where 1=1 ";
            if (queryProductName != null && !queryProductName.isEmpty()) {
                sql += "and productName like ? ";
                params.add("%" + queryProductName + "%");
            }
            if (queryProviderId != null && !queryProviderId.isEmpty()) {
                sql += "and providerId = ? ";
                params.add(queryProviderId);
            }
            if (queryIsPayment != null && !queryIsPayment.isEmpty()) {
                sql += "and isPayment = ? ";
                params.add(queryIsPayment);
            }
        }

        preparedStatement = connection.prepareStatement(sql);
        resultSet = BaseDao.executeQuery(connection, sql, preparedStatement, params.toArray(),
                resultSet);

        while (resultSet.next()) {
            billList.add(getBillList(resultSet));
        }

        BaseDao.closeResource(connection, preparedStatement, resultSet);

        return billList;
    }

billService

  1. billService
java 复制代码
    /**
     * 获取所有订单列表
     *
     * @param queryProductName 商品名称
     * @param queryProviderId  供应商
     * @param queryIsPayment   是否付款
     * @return 订单列表
     */
    List<Bill> getBillList(String queryProductName,
                           String queryProviderId, String queryIsPayment);
  1. billServiceImpl
java 复制代码
    /**
     * 获取所有订单列表
     *
     * @param queryProductName 商品名称
     * @param queryProviderId  供应商
     * @param queryIsPayment   是否付款
     * @return 订单列表
     */
    @Override
    public List<Bill> getBillList(String queryProductName, String queryProviderId,
                                  String queryIsPayment) {

        List<Bill> billList;
        Connection con = BaseDao.connection();

        try {
            billList = billDao.queryBillBy(con, queryProductName, queryProviderId, queryIsPayment);
        } catch (SQLException e) {
            throw new RuntimeException(e);
        } finally {
            BaseDao.closeResource(con, null, null);
        }

        return billList;
    }

billServlet

  1. billServlet
java 复制代码
    /**
     * 获取账单列表
     * <p>
     * 此方法负责处理账单查询请求,根据不同的查询条件(如产品名称、供应商ID、是否已支付),
     * 从数据库中获取相应的账单信息,并进行分页处理,最后将结果展示在页面上
     *
     * @param req  用于获取请求参数和设置请求属性
     * @param resp 用于实现请求转发或重定向
     * @throws ServletException 如果Servlet操作失败
     * @throws IOException      如果输入输出操作失败
     */
    private void getBill(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        // 默认值初始化
        String productName = "";
        int isPayment = 0;
        int providerId = 0;

        // 获取request参数
        String queryProductName = req.getParameter("queryProductName");
        String queryProviderId = req.getParameter("queryProviderId");
        String queryIsPayment = req.getParameter("queryIsPayment");
        String pageIndex = req.getParameter("pageIndex");

        // 默认分页设置
        int currentPageNo = 1;
        int pageSize = 5;

        // TODO: 处理查询条件,确保空值安全,isPayment、providerId --> int
        queryProductName = queryProductName == null ? "" : queryProductName;
        queryProviderId = queryProviderId == null ? "" : queryProviderId;
        queryIsPayment = queryIsPayment == null ? "" : queryIsPayment;
        currentPageNo = pageIndex == null ? currentPageNo : Integer.parseInt(pageIndex);

        // 创建BillService实例
        BillService billService = new BillServiceImpl();

        // 获取账单总数
        int totalCount = billService.getBillCount(queryProductName, queryProviderId,
                queryIsPayment);

        // 创建PageSupport实例用于分页处理
        PageSupport pageSupport = new PageSupport();

        // 设置分页参数
        pageSupport.setTotalCount(totalCount);
        pageSupport.setPageIndex(currentPageNo);
        pageSupport.setPageSize(pageSize);

        // 计算总页数
        int totalPageCount = pageSupport.getTotalPageCount();

        // 校验当前页码
        if (currentPageNo < 1) {
            currentPageNo = 1;
        } else if (currentPageNo > totalPageCount) {
            currentPageNo = totalPageCount;
        }

        // 获取账单列表
        List<Bill> billList = billService.getBillList(queryProductName, queryProviderId,
                queryIsPayment);

        // 处理完的数据存到request中,用于页面展示
        req.setAttribute("billList", billList);
        req.setAttribute("queryProductName", queryProductName);
        req.setAttribute("queryProviderId", queryProviderId);
        req.setAttribute("queryIsPayment", queryIsPayment);

        req.setAttribute("totalPageCount", totalPageCount);
        req.setAttribute("totalCount", totalCount);
        req.setAttribute("currentPageNo", currentPageNo);

        // 跳转到list页面
        req.getRequestDispatcher("/billlist.jsp").forward(req, resp);

    }
  1. web.xml

jsp

优化补充

疏通页面,修改Bug

功能点:

  1. 用户管理
  2. 供应商管理
  3. 订单管理
  4. 分页功能

分页功能异常

添加分页功能后显示

错误代码:

解释:在进行模除运算是分母为0;

解决思路及方案:

复制代码
1. 检查内容赋值,debug断点查看崩溃点,发现是 `this.totalPageCount = totalCount % pageSize == 0 ? totalCount / pageSize :totalCount / pageSize + 1;` 这部分的`pageSize=0`,检查什么时候进行赋值,赋值是否出现异常;
2. 经检查发现, `setTotalCount()` 被先调用,而 `pageSize` 还是初始值 0,所以出现报错。为避免该情况错误出现,在`setTotalCount()`方法中进行防御性默认值追加判断;为解决这次出现的问题,检查是否赋值正常,是否先赋值后调用的该方法。

没有查出数据的时候分页显示错误

错误:

You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '-5, 5' at line 1

解决思路和方案:

在SQL查询到时候设定范围选择了负数导致出现了**负数偏移量**,使用LIMIT 的时候第一个offset不能为负数;

java.sql.SQLException: Before start of result set

错误:

java.sql.SQLException: Before start of result set 是由于在尝试从 ResultSet 获取数据之前,没有调用 resultSet.next() 来将光标移动到结果集的第一行。ResultSet 初始时的光标位于第一行之前,如果不调用 next(),直接调用 getInt()、getString() 等方法就会抛出该异常。

解决思路和方案:

在获取 resultSet 后调用 resultSet.next(),确保光标移动到了有效行。

if (resultSet != null && resultSet.next()) xxx;

页面显示的时候分页功能不能用

错误:

分页功能操作的时候不能翻页

解决方案和思路:

  1. 检查SQL语句是否加上了Limit关键字,分页显示的数据需要是SQL查询的; ps:需要进行DB交互;
  2. 添加完正常分页显示,但是分页功能不能使用,检查前端代码是否正常发送请求;
  3. form表单中添加pageIndex的hidden项,如果没有 pageIndex 参数,request.getParameter("pageIndex") 就会是 null,就会报错或者默认取第一页;如果参数没有,则会出现:
    1. 默认只返回第一页数据;
    2. 或者抛出异常、找不到参数;
    3. 或者压根不知道用户想翻页;

section标签

<section> 标签在 HTML 中用于定义文档中的一个独立的、结构化的部分,通常与文档的主题、内容区分相关。它主要用于将内容分割成不同的部分,帮助提升页面的可读性和可维护性

用于提高网页的可访问性和 SEO 优化。

  • <section> 并不应该用于普通的容器(如果只是用来包裹样式或布局内容,应该使用 <div>)。它应该包含具有特定意义的内容块。
  • 使用 <section> 时,最好每个部分都有一个标题(<h1>、<h2> 等),以确保文档的语义结构清晰。

java.sql.SQLSyntaxErrorException

该问题由于 SQL 语句中使用了错误的关键字 by 而非 ORDER BY 所致。通过修正 SQL 语法即可解决。同时建议对 SQL 拼接逻辑进行规范化处理,提升代码可维护性和健壮性。

但是检查代码之后发现使用的关键字确为order by,怀疑是因为字段拼接时没有使用空格;

修改完成后,问题解决;

获取下拉框内容失败

检查代码逻辑发现读取不到下拉框列表内容,Servlet添加读取获取下拉列表信息的逻辑,debug检查后发现是

不使用ajax
  1. Servlet 中查询角色列表并转发给 JSP
java 复制代码
// UserServlet.java
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    List<Role> roleList = roleService.getAllRoles(); // 从数据库获取角色列表
    request.setAttribute("roleList", roleList); // 设置到 request 域中
    request.getRequestDispatcher("/jsp/useradd.jsp").forward(request, response);
}
  1. 在 JSP 页面中直接渲染下拉框
java 复制代码
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>

<select name="userRole" id="userRole">
    <option value="0">请选择</option>
    <c:forEach items="${roleList}" var="role">
        <option value="${role.id}">${role.roleName}</option>
    </c:forEach>
</select>

详细在实际项目 https://gitee.com/RS0582/javaSWebServlet

使用ajax,需要使用alibaba的fastjson.JSONArray
  1. 依赖导入
xml 复制代码
       <!-- https://mvnrepository.com/artifact/com.alibaba/fastjson -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>2.0.42</version>
        </dependency>
  1. 绑定jsp的标签
html 复制代码
<select name="userRole" id="userRole">  </select>
  1. 在js中使用ajax传递,获取请求的URL调用改Servlet的方法,请求成功 按照指定的格式显示
javascript 复制代码
let userRole;

$(function(){

	userRole = $("#userRole");
  
  //渲染角色下拉列表
  $.ajax({
    type:"GET",//请求类型
    url:path+"/user",//请求的url
    data:{method:"getRoleList"},//请求参数
    dataType:"json",//ajax接口(请求url)返回的数据类型
    success:function(data){//data:返回数据(json对象)
      if(data != null){ //如果数据不为空,则html添加options
        userRole.html("");
        let options = "<option value=\"0\">请选择</option>";
        for(let i = 0; i < data.length; i++){
          options += "<option value=\"" + data[i].id + "\">" + data[i].roleName + "</option>";
        }
        userRole.html(options);
      }
    },
    error:function(data){//当访问时候,404,500 等非200的错误状态码
      validateTip(userRole.next(),{"color":"red"},imgNo+" 获取用户角色列表error",false);
    }
  });
  
  // 绑定userRole
  	userRole.bind("focus",function(){
  		validateTip(userRole.next(),{"color":"#666666"},"* 请选择用户角色",false);
  	}).bind("blur",function(){
  		if(userRole.val() != null && userRole.val() > 0){
  			validateTip(userRole.next(),{"color":"green"},imgYes,true);
  		}else{
  			validateTip(userRole.next(),{"color":"red"},imgNo + " 请重新选择用户角色",false);
  		}
  	});
}
  1. 在Servlet中写调用方法 getRoleList获取Role列表
java 复制代码
        resp.setContentType("application/json");
        PrintWriter writer = resp.getWriter();
        writer.write(JSONArray.toJSONString(roleList)); // 写入json
        writer.close();
java 复制代码
    private void getRoleList(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        List<Role> roleList = roleService.getRoleList();
        resp.setContentType("application/json");
        PrintWriter writer = resp.getWriter();
        writer.write(JSONArray.toJSONString(roleList));
        writer.close();
    }


    public List<Role> getRoleList() {
        List<Role> roleList = null;
        Connection connection = DBUtil.getConnection();
        try {
            roleList = roleDao.getRoleList(connection);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            DBUtil.closeConnection(connection);
        }
        return roleList;
    }

    public List<Role> getRoleList(Connection connection) throws Exception{
        List<Role> roleList = new ArrayList<>();
        if (connection != null) {
            PreparedStatement preparedStatement = null;
            ResultSet rs = null;
            String sql = "select * from smbms_role";
            rs = DBUtil.query(connection, preparedStatement, rs, sql ,null);
            while (rs.next()) {
                roleList.add(getRoleByResult(rs));
            }
            DBUtil.closeResource(preparedStatement, rs);
        }
        return roleList;
    }

优化逻辑,根据代码检测工具(SonarQube)优化代码

追加log4j

疏通错误看log,以及抛出异常的时候总是显示异常处理 使用throw new Exception() 不好,对应点增加log4j,使用log4j管理。

  1. 依赖导入
xml 复制代码
<!-- Log4j2 Core -->
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-core</artifactId>
    <version>2.17.1</version>
</dependency>

<!-- Log4j2 API -->
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-api</artifactId>
    <version>2.17.1</version>
</dependency>

<!-- 如果你在 Web 项目中使用 Servlet,还需要这个 -->
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-web</artifactId>
    <version>2.17.1</version>
</dependency>
  1. 声明对象,导入包
java 复制代码
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;


private static final Logger logger = LogManager.getLogger(UserServlet.class);

if (logger.isDebugEnabled()) {
    logger.debug("method:" + method );
}
  1. 配置log4j2.xml
xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN">
    <Appenders>
        <!-- 控制台输出 -->
        <Console name="Console" target="SYSTEM_OUT">
          <!-- 控制台显示,显示时间 代码所在行数 log内容 -->
            <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} [%t] %-5level %logger{36} - %msg%n"/>
        </Console>
        
        <!-- 文件输出 -->
        <File name="File" fileName="target/app.log">
            <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} %-5level %logger{36} - %msg%n"/>
        </File>
    </Appenders>
    
    <Loggers>
        <!-- 根 Logger 配置 -->
        <Root level="info">
            <AppenderRef ref="Console"/>
            <AppenderRef ref="File"/>
        </Root>
        
        <!-- Custom Logger for a specific package -->
        <Logger name="com.dashangms" level="debug" additivity="false">
            <AppenderRef ref="Console"/>
            <AppenderRef ref="File"/>
        </Logger>
        
        
    </Loggers>
</Configuration>

个别部分优化点

优化点1:所有的SQL拼接语句全部使用StringBuilder 处理,减少内存雍余;

  • 原因:
    • String 是不可变对象,每次拼接都会创建新对象,效率低。
    • 特别是在循环或条件判断中频繁拼接时,性能下降明显。

优化点2:所有的字段都统一使用Constants管理

  • 原因:
    • 提高代码的一致性
    • 减少错误
    • 真正固定不变且很少被引用的值,可能没有必要创建常量

优化点3:

打印异常处理的逻辑使用log4j

  • 原因:
    • 对 'printStackTrace()' 的调用可能应当替换为更可靠的日志
    • 检查信息: 报告对无实参的 Throwable.printStackTrace() 的调用。
    • 此类语句通常用于临时调试,应当从生产代码中移除,或者替换为更稳健的日志记录工具

优化点4:使用同一构造函数,避免多次重复调用

  • 原因:
    • 减少代码重复
    • 提高代码的可维护性
      统一管理,易于更新和修改
    • 优化性能:减少对象实例化次数,提高代码的执行效率,减少不必要的资源浪费。
    • 提高代码的可读性:减少复杂度
    • 遵循面向对象编程原则
      避免不必要的重载:在面向对象编程中,使用构造函数的重载(即多个构造函数)时,应该遵循"一个构造函数处理一个逻辑"的原则。避免过多的构造函数重载可以提升代码的稳定性。

优化点5:页面调整

  • 页面foot部分颜色 :使用snipaste等工具确定主色块
  • 图标同色系嵌合:使用阿里巴巴图标库
  • 验证码
  • 页面跳转有两种方法进行,格局实际情况调整页面跳转逻辑
    • ①页面转发:request.getRequestDispatcher("/jsp/index.jsp").forward(request,response)
    • ②重定向:response.sendRedirect("/jsp/index.jsp")
场景 方法
提交表单后跳转列表页 sendRedirect
查询后展示结果页面 forward
保持地址栏不变继续处理 forward
防止用户刷新重复提交 sendRedirect
从 Servlet 跳转到 JSP 页面 forward



相关推荐
_Kayo_1 小时前
项目学习笔记 display从none切换成block
windows·笔记·学习
空の鱼3 小时前
js与vue基础学习
javascript·vue.js·学习
非ban必选3 小时前
spring-ai-alibaba之Rag 增强问答质量
java·人工智能·spring
Z_W_H_4 小时前
【SpringBoot】实战-开发接口-用户-注册
java·spring boot·spring
非ban必选4 小时前
spring-ai-alibaba官方 Playground 示例之联网搜索代码解析2
人工智能·python·spring
Blossom.1184 小时前
基于深度学习的情感分析模型:从文本数据到模型部署
人工智能·深度学习·神经网络·学习·机器学习·prompt·sklearn
球求了5 小时前
C++:现代 C++ 编程基石,C++11核心特性解析与实践
开发语言·c++·学习·visual studio
Ziegler Han5 小时前
Java的Gradle项目,使用SLF4J+Log4j2+log4j2.xml
java·log4j·slf4j
white camel5 小时前
重学SpringMVC一SpringMVC概述、快速开发程序、请求与响应、Restful请求风格介绍
java·后端·spring·restful
蒟蒻的工具人6 小时前
MySQL学习——面试版
学习·mysql·面试