JavaWeb:SMBMS 超市账单管理系统

SMBMS 超市账单管理系统

本项目是个人学习版本,基于狂神说Java的SMBMS项目,参考视频【狂神说Java】JavaWeb入门到实战

开发工具

  • IntelliJ IDEA 2019.1.4

  • MySQL 8.0

  • Tomcat 8.0

核心业务

  1. 登录注销
  2. 密码修改
  3. 用户管理
  4. 订单管理
  5. 供应商管理

准备工作

  1. 数据库表设计
  2. 搭建项目、配置Tomcat
  3. 编写实体类
  4. 编写BaseDAO
  5. 编写过滤器
  6. 导入资源

一、数据库表设计

1、用户表

2、角色表

3、地址表

4、账单表

5、供应商表


二、搭建项目

1、创建webapp项目(Maven)

注意:勾选的是maven-archetype-webapp,而不是cocoon-22-archetype-webapp

2、完善项目结构

更新XML文件:使用以下代码替换原有XML代码

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

导入依赖

  • JSP:javax.servlet.jsp-api

  • Servlet:javax.servlet-api

  • 数据库连接:mysql-connector-java

  • jstl

  • standard

<!-- JSP -->
<!-- https://mvnrepository.com/artifact/javax.servlet.jsp/javax.servlet.jsp-api -->
<dependency>
    <groupId>javax.servlet.jsp</groupId>
    <artifactId>javax.servlet.jsp-api</artifactId>
    <version>2.3.3</version>
    <scope>provided</scope>
</dependency>
<!-- Servlet -->
<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
    <version>4.0.1</version>
    <scope>provided</scope>
</dependency>
<!-- JSTL -->
<!-- https://mvnrepository.com/artifact/javax.servlet/jstl -->
<dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>jstl</artifactId>
    <version>1.2</version>
</dependency>
<!-- Standard -->
<!-- https://mvnrepository.com/artifact/taglibs/standard -->
<dependency>
    <groupId>taglibs</groupId>
    <artifactId>standard</artifactId>
    <version>1.1.2</version>
</dependency>
<!-- MySQL连接 -->
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.16</version>
</dependency>

完善项目的包结构

  1. java
    • dao:数据持久化层,用于操作数据库
    • filter:过滤器
    • pojo:实体类
    • service:业务层,调用dao层处理业务
    • servlet:调用service层处理业务
    • utils:工具类
  2. resources:存放资源文件
  3. webapp:项目资源

3、配置Tomcat

创建Tomcat

配置Tomcat

*4、在IDEA中操作数据库

也可以在SQLYog、Navicat等图形化管理工具操作数据库

新建MySQL的数据源

填写用户名、密码、URL并测试连接

注意:MySQL 8.0以上需要配置时区才可连接(在MySQL Server目录下的my.ini文件中配置)

!否则报异常Server returns invalid timezone. Go to 'Advanced' tab and set 'serverTimezone' property manually.


三、编写实体类

ORM:对象关系映射

实体类中的属性与数据库表中的字段一一对应

注意:由于Address表存放的是地址,没有实际含义,因此不编写对应实体类

1、用户类

private Integer id; // 用户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;   // 用户角色ID
private Integer createdBy;  // 创建者ID
private Date creationDate;// 创建时间
private Integer modifyBy;   // 修改者ID
private Date modifyDate;    // 修改时间

private Integer age;    // 年龄,通过当前时间-出生年份得出
private String userRoleBane;    // 用户角色名称

2、角色类

属性

private Integer id; // 角色ID
private String roleCode;    // 角色编码
private String roleName;    // 角色名
private Integer createdBy;  // 创建者ID
private Date creationDate;// 创建时间
private Integer modifyBy;   // 修改者ID
private Date modifyDate;    // 修改时间

3、账单类

属性

private Integer id; // 账单ID
private String billCode;    // 账单编码
private String productName; // 商品名
private String productDesc; // 商品描述
private String productUnit; // 商品单价
private BigDecimal productCount; // 商品数量
private BigDecimal totalPrice; // 总金额
private Integer isPayment; // 是否支付
private Integer createdBy;  // 创建者ID
private Date creationDate;// 创建时间
private Integer modifyBy;   // 修改者ID
private Date modifyDate;    // 修改时间
private Integer providerId; // 供应商ID

private String providerName;    //供应商名称

4、供应商类

属性

private Integer id; // 供应商ID
private String proCode; // 供应商编码
private String proName; // 供应商名称
private String proDesc; // 供应商描述
private String proContact; // 联系人名称
private String proPhone;   // 供应商电话
private String proAddress; // 供应商地址
private String proFax; // 供应商传真
private Integer createdBy;  // 创建者ID
private Date creationDate;// 创建时间
private Integer modifyBy;   // 修改者ID
private Date modifyDate;    // 修改时间

四、编写BaseDAO

创建数据库配置文件:db.properties

driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/smbms?useUnicode=true&characterEncoding=utf8&userSSL=false&serverTimezone=GMT%2B8
username=root
password=密码

编写公共DAO类,便于其他DAO直接调用。

  • 加载驱动

  • 获取服务器连接

  • 获取SQL执行对象

  • 执行SQL语句

  • 释放连接

public class BaseDAO {

    private static String driver;
    private static String url;
    private static String username;
    private static String password;

    static {
        try {
            InputStream in = BaseDAO.class.getClassLoader().getResourceAsStream("db.properties");
            Properties properties = new Properties();
            properties.load(in);
            driver = properties.getProperty("driver");
            url = properties.getProperty("url");
            username = properties.getProperty("username");
            password = properties.getProperty("password");
            // 加载驱动(只需一次)
            Class.forName(driver);
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取数据库连接
     *
     * @return 数据库连接
     * @throws SQLException SQL异常
     */
    private static Connection getConnection() throws SQLException {
        return DriverManager.getConnection(url, username, password);
    }

    /**
     * 获取SQL执行对象
     *
     * @param sql 待执行SQL语句
     * @return PreparedStatement对象
     * @throws SQLException SQL异常
     */
    public static PreparedStatement getPreparedStatement(String sql) throws SQLException {
        Connection c = getConnection();
        if (c != null) {
            return getConnection().prepareStatement(sql);
        }
        throw new RuntimeException("Connection为空!");
    }

    /**
     * 执行SQL语句——查询
     *
     * @param ps   SQL执行对象
     * @param args 参数
     * @return 查询结果集
     * @throws SQLException SQL异常
     */
    public static ResultSet executeQuery(PreparedStatement ps, Object... args) throws SQLException {
        for (int i = 0; i < args.length; i++) {
            ps.setObject(i + 1, args[i]);
        }
        return ps.executeQuery();
    }

    /**
     * 执行SQL语句——更新
     *
     * @param ps   SQL执行对象
     * @param args 参数
     * @return 受影响行数
     * @throws SQLException SQL异常
     */
    public static int executeUpdate(PreparedStatement ps, Object... args) throws SQLException {
        for (int i = 0; i < args.length; i++) {
            ps.setObject(i + 1, args[i]);
        }
        return ps.executeUpdate();
    }

    /**
     * @param isReleaseConnection 是否释放连接Connection
     * @param s                   Statement对象
     * @param rs                  ResultSet对象
     */
    public static void release(boolean isReleaseConnection, Statement s, ResultSet rs) {
        if (rs != null) {
            try {
                rs.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (s != null) {
            try {
                s.close();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
        if (isReleaseConnection) {
            try {
                releaseConnection();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 释放数据库连接
     *
     * @throws SQLException
     */
    private static void releaseConnection() throws SQLException {
        Connection c = getConnection();
        if (c != null) {
            c.close();
        }
    }
}

五、过滤器

字符集编码
处理页面乱码问题

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
    request.setCharacterEncoding("utf-8");
    response.setCharacterEncoding("utf-8");

    chain.doFilter(request, response);
}

注册Filter

<filter>
    <filter-name>CharacterEncodingFilter</filter-name>
    <filter-class>indi.jaywee.filter.CharacterEncodingFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>CharacterEncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

六、导入资源


开发

MVC架构

  • Module:业务模型
  • View:用户界面
  • Controller:控制器

页面发送请求给Controller(控制器),Controller调用Service(业务层) 处理逻辑,Service(Impl实现类)向DAO(持久层)发送请求,DAO与数据库交互后,将结果返回给Service,Service再将处理逻辑发送给Controller,最后Controller再调用视图展现数据到页面上。

项目架构

开发方式

自顶向下分析,自底向上实现


一、登录注销、权限拦截

(一)登录


分析前端页面可能向后台传递了哪些参数,需要后台传递哪些参数

  • 向后台传递:用户编码(userCode)、密码(userPassword)
  • 需后台传递:用于提醒登录失败的错误信息(error)

1、DAO层

UserDAO

/**
     * 获取登录用户
     *
     * @param userCode     用户编码
     * @param userPassword 用户密码
     * @return 用户
     * @throws SQLException SQL异常
     */
public User getLoginUser(String userCode, String userPassword) throws SQLException;

UserDAOImpl

userCode和 userPassword同时输入正确才匹配到数据库中用户记录

@Override
public User getLoginUser(String userCode, String userPassword) throws SQLException {

    User user = null;

    String sql = "SELECT * FROM smbms_user WHERE user_code = ? and user_password = ?"; // 编写SQL语句

    PreparedStatement ps = BaseDAO.getPreparedStatement(sql); // 获得PreparedStatement对象
    ResultSet rs = BaseDAO.executeQuery(ps, userCode, userPassword);// 执行SQL

    if (rs.next()) { // 获得结果集
        int id = rs.getInt("id");
        String userName = rs.getString("user_name");// 要用数据库表的字段名
        int gender = rs.getInt("gender");
        Date birthday = rs.getDate("birthday");
        String phone = rs.getString("phone");
        String address = rs.getString("address");
        int userRole = rs.getInt("user_role");
        int createdBy = rs.getInt("created_by");
        Date creationDate = rs.getDate("creation_date");
        int modifyBy = rs.getInt("modify_by");
        Date modifyDate = rs.getDate("modify_date");
        user = new User(id, userCode, userName, userPassword, gender, birthday,
                        phone, address, userRole, createdBy, creationDate, modifyBy, modifyDate);

        BaseDAO.release(false, ps, rs); // 连接不用关,后续业务可能需要用到
    }
    return user;
}

2、Service层

UserService

/**
     * 用户登录
     *
     * @param userCode     用户编码
     * @param userPassword 用户密码
     * @return 登录用户
     */
public User Login(String userCode, String userPassword);

UserServiceImpl

Service层通常直接调用 DAO层方法,处理异常即可

private UserDAO userDAO;

public UserServiceImpl() {
    userDAO = new UserDAOImpl();
}

@Override
public User Login(String userCode, String userPassword) {

    User user = null;

    try {
        user = userDAO.getLoginUser(userCode, userPassword);
    } catch (SQLException e) {
        e.printStackTrace();
    } finally {
        BaseDAO.release(true, null, null); // 每一层只需关闭自己的资源
    }
    return user;
}

3、Servlet层

LoginServlet

用户登录成功:将该用户存储在 Session中,重定向到后台页面

用户登录失败:设置提醒,通过请求转发到登录页

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    System.out.println("进入LoginServlet");

    String userCode = req.getParameter("userCode");
    String userPassword = req.getParameter("userPassword");

    UserService userService = new UserServiceImpl();
    User user = userService.Login(userCode, userPassword);

    if (user != null) {
        // 将用户保存到Session
        req.getSession().setAttribute(Constants.USER_SESSION, user);
        // 跳转到后台主页
        resp.sendRedirect("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 {
    doGet(req, resp);
}

注册Servlet

<servlet>
    <servlet-name>LoginServlet</servlet-name>
    <servlet-class>indi.jaywee.servlet.User.LoginServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>LoginServlet</servlet-name>
    <url-pattern>/login.do</url-pattern>
</servlet-mapping>

(二)注销

分析前端页面可能向后台传递了哪些参数,需要后台传递哪些参数

  • 由于登录状态是通过Session实现,只需移除Session即可。不需传递参数

LogoutServlet

重定向到登录页,移除当前用户的 Session

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    System.out.println("进入LogoutServlet");

    Object userSession = req.getSession().getAttribute(Constants.USER_SESSION);
    if (userSession != null) {
        resp.sendRedirect(req.getContextPath() + "/login.jsp");
        req.getSession().removeAttribute(Constants.USER_SESSION);// 移除用户Session
    }
}

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

注册Servlet

<servlet>
    <servlet-name>LogoutServlet</servlet-name>
    <servlet-class>indi.jaywee.servlet.User.LogoutServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>LogoutServlet</servlet-name>
    <url-pattern>/jsp/logout.do</url-pattern>
</servlet-mapping>

(三)权限拦截

LoginFilter:拦截未登录用户进入后台

判断 Session 是否存在:若用户已登入,Session不为 null则放行;若用户注销或 Session过期,Session为 null则拦截重定向到错误页面。

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
    HttpServletRequest req = (HttpServletRequest) request;
    HttpServletResponse resp = (HttpServletResponse) response;

    if (req.getSession().getAttribute(Constants.USER_SESSION) == null) {
        System.out.println("未登录,拦截!");
        resp.sendRedirect(req.getContextPath() + "/error.jsp");
    }

    chain.doFilter(req, resp);
}

注册Filter

<filter>
    <filter-name>LoginFilter</filter-name>
    <filter-class>indi.jaywee.filter.LoginFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>LoginFilter</filter-name>
    <url-pattern>/jsp/*</url-pattern>
</filter-mapping>

二、密码修改

分析前端页面可能向后台传递了哪些参数,需要后台传递哪些参数

  • 向后台传递:旧密码(oldPassword)、新密码(newPassword)
  • 需后台传递:密码输入错误时的提醒信息(message)

1、DAO层

UserDAO

/**
     * 修改密码
     *
     * @param id          用户ID
     * @param newPassword 新密码
     * @return 受影响行数
     * @throws SQLException SQL异常
     */
public int modifyPassword(int id, String newPassword) throws SQLException;

UserDAOImpl

@Override
public int modifyPassword(int id, String newPassword) throws SQLException {
    String sql = "UPDATE `smbms_user` SET `user_password` = ? WHERE `id` = ?";
    PreparedStatement ps = BaseDAO.getPreparedStatement(sql);
    int i = BaseDAO.executeUpdate(ps, newPassword, id);

    BaseDAO.release(false, ps, null); // 释放连接

    return i;
}

2、Service层

UserService

/**
     * 修改密码
     *
     * @param id          用户ID
     * @param newPassword 新密码
     * @return 是否修改成功
     */
public boolean modifyPassword(int id, String newPassword);

UserServiceImpl

@Override
public boolean modifyPassword(int id, String newPassword) {
    boolean flag = false;
    try {
        if (userDAO.modifyPassword(id, newPassword) > 0) {
            flag = true;
        }
    } catch (SQLException e) {
        e.printStackTrace();
    } finally {
        BaseDAO.release(true, null, null);
    }
    return flag;
}

3、Servlet层

UserServlet:实现服务器端验证

本项目中,多个页面用到 UserServlet,只是调用的方法不同;

考虑到复用性,抽取方法。判断页面发送的是哪个请求,再调用相应方法

可以用 if 语句或 switch-case语句,如果是 switch-case

注意:一个页面可能发送 1个以上的请求,所以要用多重 if,而不是if-else;case后面不能马上 break

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    System.out.println("进入了UserServlet");

    String method = req.getParameter("method");
    if (method != null) {
        switch (method) { // 判断请求
            case "verifyPwd":
                this.verifyPwd(req, resp);
            case "modifyPwd":
                this.modifyPwd(req, resp);
            case "queryUserList":
                this.queryUserList(req, resp);
                break;
        }
    }
}

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

3.1、旧密码验证

UserServlet

服务端实现:对比用户输入的旧密码和 Session中的密码

/**
     * 验证旧密码
     *
     * @param req
     * @param resp
     * @throws ServletException
     * @throws IOException
     */
private void verifyPwd(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

    User user = null;
    String password = null;
    String oldpassword = req.getParameter("oldpassword");

    Object o = req.getSession().getAttribute(Constants.USER_SESSION);

    if (o != null) {
        user = (User) o;
        password = user.getUserPassword();
    }
    if (StringUtils.isNullOrEmpty(oldpassword) && !oldpassword.equals(password)) { // 旧密码不为空或空值,并且输入正确(注意取反)
        req.setAttribute(Constants.MESSAGE, "旧密码输入错误");
        req.getRequestDispatcher("pwdmodify.jsp").forward(req, resp);

    }
}

优化——Ajax验证

private void verifyPwd(HttpServletRequest req, HttpServletResponse resp) throws IOException {

    // Ajax实现
    User user = null;
    String password = null;

    String oldpassword = req.getParameter("oldpassword");
    Object o = req.getSession().getAttribute(Constants.USER_SESSION);

    HashMap<String, String> resultMap = new HashMap<>();

    if (o == null) { // o为空
        resultMap.put("result", "sessionerror");
    } else if (StringUtils.isNullOrEmpty(oldpassword)) { // 密码为空
        resultMap.put("result", "error");
    } else {
        user = (User) o;
        password = user.getUserPassword();
        if (oldpassword.equals(password)) { // 密码输入正确
            resultMap.put("result", "true");
        } else { // 密码输入错误
            resultMap.put("result", "false");
        }
    }

    resp.setContentType("application/json");
    PrintWriter writer = resp.getWriter();
    writer.write(JSONArray.toJSONString(resultMap)); // 将Map对象转化为JSON字符串
    writer.flush();
    writer.close();
}

pwdmodify.js

$.ajax({
    type: "GET",
    url: "/smbms/jsp/user.do",
    //url:path+"/jsp/user.do",
    data: {method: "verifyPwd", oldpassword: oldpassword.val()},	// Ajax传递的参数
    // 等价于:path+/jsp/user.do?method=pwdmodify&oldpassword=oldpassword.val();
    dataType: "json",	//主流开发都是用JSON实现前后端交互
    success: function (data) {
        if (data.result == "true") {//旧密码正确
            validateTip(oldpassword.next(), {"color": "green"}, imgYes, true);
        } else if (data.result == "false") {//旧密码输入不正确
            validateTip(oldpassword.next(), {"color": "red"}, imgNo + " 原密码输入不正确", false);
        } else if (data.result == "sessionerror") {//当前用户session过期,请重新登录
            validateTip(oldpassword.next(), {"color": "red"}, imgNo + " 当前用户session过期,请重新登录", false);
        } else if (data.result == "error") {//旧密码输入为空
            validateTip(oldpassword.next(), {"color": "red"}, imgNo + " 请输入旧密码", false);
        }
    },
    error: function (data) {
        //请求出错
        validateTip(oldpassword.next(), {"color": "red"}, imgNo + " 请求错误", false);
    }
});

3.2、设置新密码

UserServlet

判断新密码不为空或者空值,才调用 Service层修改密码。密码修改成功则移除当前用户 Session

/**
     * 修改密码
     *
     * @param req
     * @param resp
     * @throws ServletException
     * @throws IOException
     */
private void modifyPwd(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

    User user;
    int id = 0;
    String newpassword = req.getParameter("newpassword");
    Object o = req.getSession().getAttribute(Constants.USER_SESSION);

    if (o != null) {
        user = (User) o;
        id = user.getId();
    }
    verifyPwd(req, resp);
    if (!StringUtils.isNullOrEmpty(newpassword)) { // 新密码 不为空或空值(注意取反)

        UserService us = new UserServiceImpl();

        if (us.modifyPassword(id, newpassword)) { // 密码修改成功
            req.setAttribute(Constants.MESSAGE, "密码修改成功,请使用新密码登录");
            req.getSession().removeAttribute(Constants.USER_SESSION);

        } else { // 密码修改失败
            req.setAttribute(Constants.MESSAGE, "密码修改失败");
        }
    } else {
        req.setAttribute(Constants.MESSAGE, "新密码输入有误");
    }
    req.getRequestDispatcher("pwdmodify.jsp").forward(req, resp);
}

注册Servlet

<servlet>
    <servlet-name>UserServlet</servlet-name>
    <servlet-class>indi.jaywee.servlet.User.UserServlet</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>UserServlet</servlet-name>
    <url-pattern>/jsp/user.do</url-pattern>
</servlet-mapping>

三、用户管理

先分析前端页面可能向后台传递了哪些参数,需要后台传递哪些参数。

  1. 查询功能

    • 向后台传递:用户名(userName)、用户角色ID(role)
    • 需后台传递:用户角色下拉框的用户角色列表(roleList)
  2. 用户列表展示

    • 需后台传递:用户列表(userList)
  3. 分页支持

    • 在后台设置:页面容量(pageSIze)

    • 向后台传递:当前页码(currentPageNo)

    • 需后台传递:页码(pageNo)、总条目数(totalCount)、总页数(totalPageCount)

(一)用户总数

1、DAO层

UserDAO

前端页面的搜索功能,可能会传入用户名和角色,因此需要用到这 2个参数

/**
     * 获取用户总数
     *
     * @param userName 用户名
     * @param userRole 用户角色ID
     * @return 用户总数
     * @throws SQLException SQL异常
     */
public int getUserCount(String userName, int userRole) throws SQLException;

UserDAOImpl

动态SQL使用 StringBuffer或 StringBuilder代替 String(提高拼接效率,在这里效果可能没有那么明显),注意拼接 SQL语句的空格问题

ArrayList: 由于不确定前端页面是否有输入userName和 userRole,即这 2个属性可能为空值,此时如果调用 SQL并传递空值,相当于往占位符填入2个 null,显然不可行。因此采用 ArrayList来动态存储参数列表。

如果 userName和 userRole不为空,则往ArrayList中添加参数,并且 userName采用模糊搜索

@Override
public int getUserCount(String userName, int userRole) throws SQLException {

    int count = 0;
    ArrayList<Object> params = new ArrayList<>(); // 使用ArrayList,动态增加参数(注意转换成数组)

    StringBuffer sql = new StringBuffer("SELECT COUNT(1) AS `count`\n" +
            "FROM `smbms_user` AS `u`,\n" +
            "     `smbms_role` AS `r`\n" +
            "WHERE `u`.`user_role` = `r`.`id`");

    if (!StringUtils.isNullOrEmpty(userName)) {
        sql.append(" AND `user_name` LIKE ?");
        params.add("%" + userName + "%"); // 模糊搜索
    }
    if (userRole > 0) {
        sql.append(" AND `user_role` = ?");
        params.add(userRole);
    }

    PreparedStatement ps = BaseDAO.getPreparedStatement(sql.toString());
    ResultSet rs = BaseDAO.executeQuery(ps, params.toArray());

    System.out.println(sql.toString());

    if (rs.next()) {
        count = rs.getInt("count");
    }
    BaseDAO.release(false, ps, rs);

    return count;
}

2、Service层

UserService

/**
     * 获取用户总数
     *
     * @param userName 用户名
     * @param userRole 用户角色ID
     * @return 用户总数
     * @throws SQLException SQL异常
     */
public int getUserCount(String userName, int userRole);

UserServiceImpl

@Override
public int getUserCount(String userName, int userRole) {
    int count = 0;

    try {
        count = userDAO.getUserCount(userName, userRole);
    } catch (SQLException e) {
        e.printStackTrace();
    } finally {
        BaseDAO.release(true, null, null);
    }

    return count;
}

(二)用户列表

1、DAO层

UserDAO

/**
     * 获取用户列表
     *
     * @param userName      用户名
     * @param userRole      用户角色ID
     * @param currentPageNo 当前页码
     * @param pageSize      页面容量
     * @return 用户列表
     * @throws SQLException SQL异常
     */
public List<User> getUserList(String userName, int userRole, int currentPageNo, int pageSize) throws SQLException;

UserDAOImpl

类似 getUserCount(),在动态SQL以及参数列表的基础上,加入了分页功能(通过MySQL的 limit实现)。

@Override
public List<User> getUserList(String userName, int userRole, int currentPageNo, int pageSize) throws SQLException {

    List<User> userList = new ArrayList<>(); // 存放用户列表

    StringBuffer sql = new StringBuffer("select u.*, r.role_name\n" +
                                        "from `smbms_user` as u,\n" +
                                        "     `smbms_role` as r\n"
                                        +
                                        "where u.user_role = r.id");

    List<Object> params = new ArrayList<>(); // 存放SQL参数

    if (!StringUtils.isNullOrEmpty(userName)) {
        sql.append(" and u.user_name like ?");
        params.add("%" + userName + "%");
    }
    if (userRole > 0) {
        sql.append(" and u.user_role = ?");
        params.add(userRole);
    }
    // 分页
    sql.append(" order by u.creation_date desc limit ?,?");
    int startIndex = (currentPageNo - 1) * pageSize; // 每页的起始索引
    params.add(startIndex);
    params.add(pageSize);

    PreparedStatement ps = BaseDAO.getPreparedStatement(sql.toString());

    ResultSet rs = BaseDAO.executeQuery(ps, params.toArray());

    while (rs.next()) {
        User user = new User();
        user.setId(rs.getInt("id"));
        user.setUserCode(rs.getString("user_code"));
        user.setUserName(rs.getString("user_name"));
        user.setGender(rs.getInt("gender"));
        user.setBirthday(rs.getDate("birthday"));
        user.setAge();
        user.setPhone(rs.getString("phone"));
        user.setUserRoleName(rs.getString("role_name"));

        userList.add(user);
    }
    BaseDAO.release(false, ps, rs);

    return userList;
}

2、Service层

UserService

/**
     * 获取用户列表
     *
     * @param userName      用户名
     * @param userRole      用户角色ID
     * @param currentPageNo 当前页码
     * @param pageSize      页面容量
     * @return 用户列表
     */
public List<User> getUserList(String userName, int userRole, int currentPageNo, int pageSize);

UserServiceImpl

@Override
public List<User> getUserList(String userName, int userRole, int currentPageNo, int pageSize) {

    List<User> userList = null;

    try {
        userList = userDAO.getUserList(userName, userRole, currentPageNo, pageSize);
    } catch (SQLException e) {
        e.printStackTrace();
    } finally {
        BaseDAO.release(true, null, null);
    }
    return userList;
}

(三)角色列表

1、DAO层

RoleDAO

/**
     * 获取角色列表
     *
     * @return 角色列表
     * @throws SQLException SQL异常
     */
List<Role> getRoleList() throws SQLException;

RoleDAOImpl

@Override
public List<Role> getRoleList() throws SQLException {
    List<Role> roleList = new ArrayList<>();

    String sql = "select * from smbms_role";
    PreparedStatement ps = BaseDAO.getPreparedStatement(sql);

    ResultSet rs = BaseDAO.executeQuery(ps);

    while (rs.next()) {
        Role role = new Role();
        role.setId(rs.getInt("id"));
        role.setRoleCode(rs.getString("role_code"));
        role.setRoleName(rs.getString("role_name"));

        roleList.add(role);
    }

    BaseDAO.release(false, ps, rs);

    return roleList;
}

2、Service层

RoleService

/**
     * 获取角色列表
     *
     * @return 角色列表
     * @throws SQLException SQL异常
     */
List<Role> getRoleList() throws SQLException;

RoleServiceImpl

@Override
public List<Role> getRoleList() throws SQLException {
    List<Role> roleList = new ArrayList<>();

    String sql = "select * from smbms_role";
    PreparedStatement ps = BaseDAO.getPreparedStatement(sql);

    ResultSet rs = BaseDAO.executeQuery(ps);

    while (rs.next()) {
        Role role = new Role();
        role.setId(rs.getInt("id"));
        role.setRoleCode(rs.getString("role_code"));
        role.setRoleName(rs.getString("role_name"));

        roleList.add(role);
    }

    BaseDAO.release(false, ps, rs);

    return roleList;
}

(四)Servlet

userRole如果前端页面没有选择角色,即没有向后台传递 userRole,则默认为 0(因为Service中当userRole >0才会拼接字符串);如果有选择角色,则将从页面接收到的 userRole转化为 int,赋给要用于查询的 userRole。

pageIndex类似userRole,只是初次打开用户管理页的时候默认值为1,在pageIndex有变化时,才

设置分页支持所需属性时,要先设置 pageSize,再设置 TotalPageCount(因为 TotalPageCount是基于 pageSize计算的)

private void queryUserList(HttpServletRequest req, HttpS。再ervletResponse resp) throws ServletException, IOException {
    UserService userService = new UserServiceImpl();
    RoleService roleService = new RoleServiceImpl();

    List<User> userList = null; // 用于展示用户
    List<Role> roleList = null; // 用于select下拉框

    // 搜索功能:用户名、角色ID
    String queryUserName = req.getParameter("queryname");   // 用户名
    String tempUserRole = req.getParameter("queryUserRole");// 前端接收到的角色ID,可能为空
    int queryUserRole = 0; // 实际使用的角色ID

    if (!StringUtils.isNullOrEmpty(tempUserRole)) {
        queryUserRole = Integer.parseInt(tempUserRole);
    }

    // 分页:页面容量、页码、总条目数、总页数
    int pageSize = 5; // 页面容量
    String pageIndex = req.getParameter("pageIndex");   // 前端接收的页码
    int currentPageNo = 1; // 实际使用的页码,初次加载是第一页

    if (!StringUtils.isNullOrEmpty(pageIndex)) {
        currentPageNo = Integer.parseInt(pageIndex);
    }

    int totalCount = userService.getUserCount(queryUserName, queryUserRole); // 总条目数
    // 调用PageSupport实现上一页、下一页
    PageSupport pageSupport = new PageSupport();
    pageSupport.setCurrentPageNo(currentPageNo); // 设置当前页码
    pageSupport.setPageSize(pageSize);  // 设置页面容量
    pageSupport.setTotalCount(totalCount);  // 设置总条目数(基于pageSize的计算,所以要在setPageSize之后)

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

    // 限制首尾页
    if (currentPageNo < 1) {
        currentPageNo = 1;
    } else if (currentPageNo > totalPageCount) {
        currentPageNo = totalPageCount;
    }

    // 得到用户列表、角色列表
    userList = userService.getUserList(queryUserName, queryUserRole, currentPageNo, pageSize);
    roleList = roleService.getRoleList();

    // 传递页面所需参数
    req.setAttribute("userList", userList);
    req.setAttribute("roleList", roleList);

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

    req.getRequestDispatcher("userlist.jsp").forward(req, resp);
}

待完成

  • 用户:增删改
  • 订单、供应商管理
posted @ 2021-07-14 15:39  Jaywee  阅读(1805)  评论(0编辑  收藏  举报

👇