JavaWeb:SMBMS 超市账单管理系统
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);
}
待完成
- 用户:增删改
- 订单、供应商管理