SMBMS 超市賬單管理系統
本項目是個人學習版本,基於狂神說Java
的SMBMS項目,參考視頻【狂神說Java】JavaWeb入門到實戰
開發工具
-
IntelliJ IDEA 2019.1.4
-
MySQL 8.0
-
Tomcat 8.0
核心業務
- 登錄注銷
- 密碼修改
- 用戶管理
- 訂單管理
- 供應商管理
准備工作
- 數據庫表設計
- 搭建項目、配置Tomcat
- 編寫實體類
- 編寫BaseDAO
- 編寫過濾器
- 導入資源
一、數據庫表設計
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>
完善項目的包結構
- java
- dao:數據持久化層,用於操作數據庫
- filter:過濾器
- pojo:實體類
- service:業務層,調用dao層處理業務
- servlet:調用service層處理業務
- utils:工具類
- resources:存放資源文件
- 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>
三、用戶管理
先分析前端頁面可能向后台傳遞了哪些參數,需要后台傳遞哪些參數。
-
查詢功能
- 向后台傳遞:用戶名(userName)、用戶角色ID(role)
- 需后台傳遞:用戶角色下拉框的用戶角色列表(roleList)
-
用戶列表展示
- 需后台傳遞:用戶列表(userList)
-
分頁支持
-
在后台設置:頁面容量(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);
}
待完成
- 用戶:增刪改
- 訂單、供應商管理