Java Web: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);
}

待完成

  • 用戶:增刪改
  • 訂單、供應商管理


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM