【项目实践】SMBMS(Javaweb版)汇总版
文章目录
- 前期准备工作
- 数据库、数据表
- 创建web项目
- 创建项目文件目录
- 配置Tomcat,导入依赖
- 建立实体类
- 编写基础公共方法类
- 导入基础资源
- 登录功能
- 登录页面
- 持久层dao层的用户登录及接口实现
- dao层接口
- 实现所需的方法
- 业务层sevice层的接口的实现
- 接口
- 实现相关的业务逻辑
- 编写servlet的业务逻辑
- 编写业务逻辑
- 映射接口路径
- 登出、注册、注销、修改
- 登出操作的实现逻辑及方式
- 防止用户登出后可以继续访问
- 修改密码功能实现
- 导入jsp
- 实现Dao层数据接口
- 实现Service层业务接口
- 注册Servlet
- 注册和注销 用户的方式(优化)
- 导入jsp
- 实现Dao层的数据逻辑
- 实现Service逻辑
- 注册Servlet
- 用户管理模块
- 前期准备
- 共同工具类
- 导入前端代码
- 获取用户数量
- UserDao
- UserService
- 获取用户列表
- UserDao
- UserService
- 获取用户角色 列表
- RoleDao
- RoleService
- 编写查询用户的Servlet
- doGet方法
- query方法
- 添加用户子模块
- 导入jsp请求按钮
- UserDao逻辑
- UserService逻辑
- 删除用户子模块
- 导入jsp请求按钮
- UserDao逻辑
- UserService逻辑
- 修改用户子模块
- 导入jsp请求按钮,检查
- UserDao逻辑
- UserService逻辑
- 查询用户子模块
- 导入jsp请求按钮,检查
- Servlet
- UserService逻辑 :getUserById
- UserDao
- 供应商管理
- 前期准备
- 增加供应商
- PrivodeDao
- ProviderService
- ProviderServlet
- 删除供应商
- ProviderDao
- ProviderService
- ProviderServlet
- 更改供应商信息
- ProviderDao
- ProviderService
- ProviderServlet
- 查询供应商信息
- ProviderDao
- ProviderService
- ProviderServlet
- 订单管理
- 前期准备
- 新增订单
- billDao
- billService
- billServlet
- jsp
- 取消订单
- billDao
- billService
- billServlet
- jsp
- 更改订单信息
- billDao
- billService
- billServlet
- jsp
- 查询订单信息
- billDao
- billService
- billServlet
- jsp
- 优化补充
- 疏通页面,修改Bug
- 功能点:
- 分页功能异常
- 没有查出数据的时候分页显示错误
- java.sql.SQLException: Before start of result set
- 页面显示的时候分页功能不能用
- section标签
- java.sql.SQLSyntaxErrorException
- 获取下拉框内容失败
- 不使用ajax
- 使用ajax,需要使用alibaba的`fastjson.JSONArray`
- 优化逻辑,根据代码检测工具(SonarQube)优化代码
- 追加log4j
- 个别部分优化点
前期准备工作
数据库、数据表
设计ER图,考虑需求逻辑,设计表结构,一般格式使用utf8。
确定使用的数据库,安装MySQL。navicat或Dbeaver 操作数据库。
本地练习的数据库选用MySQL,账号密码使用root
;
创建web项目
安装IDE开发工具:idea/eclipse
配置maven,jdk,tomcat;
maven 更改setting.xml中的路径源,调整为国内的内容。
使用idea创建一个maven web 项目,配置下tomcat,启动下看看是否正常。
创建项目文件目录
明确当前是属于javaweb项目,需要使用servlet进行交互。
创建目录结构
- src
- main
- java
- com
- common
- Constants.java //共通常量
- utils // 共同使用的软件包
- thisprojiect
- dao //与数据库交互的持久层
- pojo // javaBean实体类
- sevice // 实现逻辑的业务逻辑层
- servlet // 处理请求转发实现相关功能
- filter // 拦截器,处理数据编码
- common
- com
- resources //配置文件路径
- webapp // 网站资源
- WEB-INF // 网站信息
- index.jsp
- java
- test // 测试目录
- main
配置Tomcat,导入依赖
将需要用到几种依赖环境,一定要及时更新,
- javax.servlet-api
- javax.servlet.jsp-api
- mysql-connector-java
- jstl-api // jstl的接口和标签规范
- standard // jstl的具体实现
确保 jstl 和 standard 的版本一致
<dependencies><!-- servlet--><dependency><groupId>javax.servlet</groupId><artifactId>javax.servlet-api</artifactId><version>4.0.1</version></dependency><!-- jsp--><dependency><groupId>javax.servlet.jsp</groupId><artifactId>javax.servlet.jsp-api</artifactId><version>2.3.3</version></dependency><!-- mysql--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.24</version></dependency><!-- JSTL表达式--><dependency><groupId>javax.servlet.jsp.jstl</groupId><artifactId>jstl-api</artifactId><version>1.2</version></dependency><!-- standard--><dependency><groupId>taglibs</groupId><artifactId>standard</artifactId><version>1.1.2</version></dependency>
</dependencies>
建立实体类
根据前面设计的表结构,作成javaBean。
生成相对应的getter,setter方法
编写javabean的时候要注意数据类型。
目录:src.java.com.myprojiect.pojo
package com.dashangms.pojo;import java.util.Date;public class User {private Integer id;private String userCode;private String userName;private String userPassword;private Integer gender;private Date birthday;private String phone;private String address;private Integer userRole;private Integer createdBy; //创建者private Date createDate; // 创建时间private Integer modifyBy; //更新者private Date modifyDate; //更新时间private Integer age; //年龄private String userRoleName; //用户角色名称public User() {}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}public String getUserRoleName() {return userRoleName;}public void setUserRoleName(String userRoleName) {this.userRoleName = userRoleName;}public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getUserCode() {return userCode;}public void setUserCode(String userCode) {this.userCode = userCode;}public String getUserName() {return userName;}public void setUserName(String userName) {this.userName = userName;}public String getUserPassword() {return userPassword;}public void setUserPassword(String userPassword) {this.userPassword = userPassword;}public Integer getGender() {return gender;}public void setGender(Integer gender) {this.gender = gender;}public Date getBirthday() {return birthday;}public void setBirthday(Date birthday) {this.birthday = birthday;}public String getPhone() {return phone;}public void setPhone(String phone) {this.phone = phone;}public String getAddress() {return address;}public void setAddress(String address) {this.address = address;}public Integer getUserRole() {return userRole;}public void setUserRole(Integer userRole) {this.userRole = userRole;}public Integer getCreatedBy() {return createdBy;}public void setCreatedBy(Integer createdBy) {this.createdBy = createdBy;}public Date getCreateDate() {return createDate;}public void setCreateDate(Date createDate) {this.createDate = createDate;}public Integer getModifyBy() {return modifyBy;}public void setModifyBy(Integer modifyBy) {this.modifyBy = modifyBy;}public Date getModifyDate() {return modifyDate;}public void setModifyDate(Date modifyDate) {this.modifyDate = modifyDate;}@Overridepublic String toString() {return "User{" +"id=" + id +", userCode='" + userCode + '\'' +", userName='" + userName + '\'' +", userPassword='" + userPassword + '\'' +", gender=" + gender +", birthday=" + birthday +", phone='" + phone + '\'' +", address='" + address + '\'' +", userRole=" + userRole +", createdBy=" + createdBy +", createDate=" + createDate +", modifyBy=" + modifyBy +", modifyDate=" + modifyDate +", age=" + age +", userRoleName='" + userRoleName + '\'' +'}';}
}
编写基础公共方法类
数据库交互需要用到的方法
目录:src.java.com.myprojiect.dao
不要忘记需要先加载数据库配置文件,写入static静态方法中;
数据库交互会有以下几种场合:
- 数据库连接
- 数据库关闭
- 数据库查询:查询功能
- 数据库更新:增删改功能
做好异常保护,try … catch…
package com.dashangms.dao;import java.io.InputStream;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Properties;public class BaseDao {private static String driver;private static String url;private static String username;private static String password;// 静态代码块 类加载的时候初始化static {// 创建Properties对象,用于加载配置文件Properties properties = new Properties();// 通过类加载器获取配置文件输入流InputStream inputStream = BaseDao.class.getClassLoader().getResourceAsStream("db.properties");// 尝试加载配置文件并获取数据库连接属性try {// 加载配置文件到Properties对象properties.load(inputStream);// 从Properties对象中获取数据库驱动属性driver = properties.getProperty("driver");// 从Properties对象中获取数据库URL属性url = properties.getProperty("url");// 从Properties对象中获取数据库用户名属性username = properties.getProperty("username");// 从Properties对象中获取数据库密码属性password = properties.getProperty("password");} catch (Exception e) {// 打印异常信息,便于调试和日志记录e.printStackTrace();}}/*** 获取数据库连接* <p>* 此方法旨在建立与特定数据库的连接,使用预定义的驱动程序、URL、用户名和密码* 它封装了数据库连接的创建过程,对外提供了一个简单的接口** @return Connection 数据库连接对象如果无法建立连接,则返回null*/public static Connection connection() {Connection connection = null;try {// 加载并注册JDBC驱动程序Class.forName(driver);// 使用指定的URL、用户名和密码建立数据库连接connection = java.sql.DriverManager.getConnection(url, username, password);} catch (Exception e) {// 捕获并打印异常信息,便于问题追踪和调试e.printStackTrace();}// 返回数据库连接对象return connection;}/*** 执行SQL查询语句并返回结果集* 此方法用于简化数据库查询操作,它封装了使用PreparedStatement执行查询的过程* 它通过传入的Connection对象准备SQL语句,使用参数数组填充SQL语句中的占位符,* 然后执行查询并返回结果集** @param connection 数据库连接对象,用于执行SQL语句* @param sql SQL查询语句,可能包含占位符* @param preparedStatement 预编译的SQL语句对象,用于设置参数和执行查询* @param params 参数数组,用于填充SQL语句中的占位符* @param resultSet 结果集对象,用于存储查询结果* @return 返回执行SQL查询后得到的结果集* @throws SQLException 如果数据库操作失败,抛出此异常*/public static ResultSet executeQuery(Connection connection, String sql,PreparedStatement preparedStatement, Object[] params,ResultSet resultSet) throws SQLException {// 准备SQL语句preparedStatement = connection.prepareStatement(sql);// 填充SQL语句中的占位符for (int i = 0; i < params.length; i++) {preparedStatement.setObject(i + 1, params[i]);}// 执行查询并获取结果集resultSet = preparedStatement.executeQuery();// 返回结果集return resultSet;}/*** 执行数据库更新操作* 该方法用于执行INSERT、UPDATE或DELETE等数据库更新操作* 它接受一个数据库连接、一个SQL语句、一个预编译的语句对象和一组参数作为输入* 参数用于填充预编译的SQL语句中的占位符** @param connection 数据库连接对象,用于与数据库建立连接* @param sql 待执行的SQL语句,可能包含占位符* @param preparedStatement 预编译的SQL语句对象,用于执行更新操作* @param params 用于替换SQL语句中占位符的实际参数数组* @return 返回更新操作影响的行数* @throws SQLException 如果数据库操作失败,抛出此异常*/public static int executeUpdate(Connection connection, String sql,PreparedStatement preparedStatement, Object[] params) throws SQLException {// 准备SQL语句:根据提供的SQL字符串和连接对象创建一个预编译的语句对象preparedStatement = connection.prepareStatement(sql);// 设置参数:遍历参数数组,将每个参数设置到预编译的语句中相应的占位符位置for (int i = 0; i < params.length; i++) {preparedStatement.setObject(i + 1, params[i]);}// 执行更新:执行预编译的SQL语句,并获取影响的行数// 返回结果:返回更新操作影响的行数return preparedStatement.executeUpdate();}/*** 关闭数据库连接方法** @param connection 数据库连接对象,传入此对象以进行关闭操作*/public static void closeConnection(Connection connection) {// 检查连接对象是否非空,以避免尝试关闭空连接导致的异常if (connection != null) {try {// 尝试关闭数据库连接connection.close();} catch (Exception e) {// 捕获并打印关闭连接时可能发生的异常,便于问题追踪和定位e.printStackTrace();}}}/*** 关闭数据库连接和声明对象* 此方法旨在简化资源管理,通过一次性关闭所有相关资源来防止资源泄露和潜在的内存问题** @param conn 数据库连接对象,用于与数据库通信* @param preparedStatement 预编译的SQL语句对象,用于执行SQL查询或更新* @param resultSet 结果集对象,包含查询结果* @return boolean 表示是否成功关闭所有资源true表示成功,false表示过程中发生异常*/public static boolean closeResource(Connection conn,PreparedStatement preparedStatement,ResultSet resultSet){boolean flag = true;//检查连接对象是否不为空,如果不为空,则尝试关闭连接if(conn!=null){try {conn.close();//GC回收conn = null;} catch (SQLException e) {e.printStackTrace();flag = false;}}//检查预编译的SQL语句对象是否不为空,如果不为空,则尝试关闭它if(preparedStatement!=null){try {preparedStatement.close();//GC回收preparedStatement = null;} catch (SQLException e) {e.printStackTrace();flag = false;}}//检查结果集对象是否不为空,如果不为空,则尝试关闭它if(resultSet!=null){try {resultSet.close();//GC回收resultSet = null;} catch (SQLException e) {e.printStackTrace();flag = false;}}//返回资源关闭操作是否成功return flag;}}
导入基础资源
将需要用到的web相关内容导入进去,从git上找一个通用的页面模板导入,改一下请求的路径
登录功能
登录页面主要有两点功能:
- 已有用户登录
- 未有用户注册
登录页面
持久层dao层的用户登录及接口实现
与数据库交互
dao层接口
package com.dashangms.dao.user;import com.dashangms.pojo.User;import java.sql.Connection;
import java.util.List;public interface UserDao {/*** 用户登录查询** @param connection 数据库连接对象* @param userCode 用户编码* @param userPassword 用户密码* @return 登录用户对象* @throws Exception 异常处理*/User getLoginUser(Connection connection, String userCode, String userPassword) throws Exception;/*** 更新用户密码** @param connection 数据库连接对象* @param id 用户id* @param newPwd 新密码* @return 影响行数* @throws Exception 异常处理*/int updatePwd(Connection connection, Integer id, String newPwd) throws Exception;/*** 获取用户数量(根据用户名和角色筛选)** @param connection 数据库连接对象* @param queryUserName 查询的用户名* @param queryUserRole 查询的角色* @return 用户数量* @throws Exception 异常处理*/int getUserCount(Connection connection, String queryUserName, Integer queryUserRole) throws Exception;List<User> getUserList(Connection connection, String userName, int userRole,int currentPageNo, int pageSize) throws Exception;/*** 根据用户id获取用户信息** @param connection 数据库连接对象* @param id 用户id* @return 用户对象* @throws Exception 异常处理*/User getUserById(Connection connection, int id) throws Exception;/*** 修改用户信息** @param connection 数据库连接对象* @param user 用户对象* @return 影响行数* @throws Exception 异常处理*/int modify(Connection connection, User user) throws Exception;/*** 根据用户id删除用户** @param connection 数据库连接对象* @param delId 删除的用户id* @return 影响行数* @throws Exception 异常处理*/int deleteUserById(Connection connection, Integer delId) throws Exception;/*** 添加用户** @param connection 数据库连接对象* @param user 用户对象* @return 影响行数* @throws Exception 异常处理*/int add(Connection connection, User user) throws Exception;/*** 检查用户编码是否存在** @param connection 数据库连接对象* @param userCode 用户编码* @return 用户对象* @throws Exception 异常处理*/User selectUserCodeExist(Connection connection, String userCode) throws Exception;
}
实现所需的方法
package com.dashangms.dao.user;import com.common.utils.DateUtils;
import com.dashangms.dao.BaseDao;
import com.dashangms.pojo.User;
import com.mysql.cj.util.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;public class UserDaoImpl implements UserDao {// 获取一个 Logger 实例private static final Logger logger = LogManager.getLogger(UserDaoImpl.class);private final StringBuilder sb = new StringBuilder();/*** 用户登录查询** @param connection 数据库连接对象* @param userCode 用户编码* @param userPassword 用户密码* @return 登录用户对象* @throws Exception 异常处理*/@Overridepublic User getLoginUser(Connection connection, String userCode, String userPassword) throws Exception {User user = null;// 检查数据库连接是否已建立if (connection != null) {PreparedStatement preparedStatement;// 清空StringBuilder对象sb.delete(0, sb.length());// SQL查询语句,用于验证用户登录sb.append("select * from smbms_user where userCode = ? and userPassword = ?");if (logger.isDebugEnabled()) {logger.debug("getLoginUser SQL: " + sb);logger.debug("getLoginUser params: " + userCode + " " + userPassword);}// 预编译SQL语句,提高性能和安全性preparedStatement = connection.prepareStatement(sb.toString());// 设置查询参数preparedStatement.setString(1, userCode);preparedStatement.setString(2, userPassword);// 执行查询ResultSet resultSet = preparedStatement.executeQuery();// Object[] params = {userCode, userPassword} ;// resultSet = BaseDao.executeQuery(connection, sql, preparedStatement,params,// resultSet);// 处理查询结果 resultSet != nullif (resultSet.next()) {user = getUserByResult(resultSet);}// 关闭资源,避免内存泄漏BaseDao.closeResource(connection, preparedStatement, resultSet);}return user;}/*** 更新用户密码** @param connection 数据库连接对象* @param id 用户id* @param newPwd 新密码* @return 影响行数* @throws Exception 异常处理*/@Overridepublic int updatePwd(Connection connection, Integer id, String newPwd) throws Exception {// 初始化影响行数为0int updateRow = 0;// 检查数据库连接是否为空if (connection != null) {// 预编译SQL语句以提高性能和安全性PreparedStatement preparedStatement;sb.delete(0, sb.length());sb.append("update smbms_user set userPassword = ? where id = ?");String sql = sb.toString();preparedStatement = connection.prepareStatement(sql);// 设置SQL语句参数preparedStatement.setString(1, newPwd);preparedStatement.setInt(2, id);// 执行更新操作并获取影响行数updateRow = preparedStatement.executeUpdate();// 关闭数据库连接和预编译语句资源BaseDao.closeResource(connection, preparedStatement, null);}// 返回影响行数return updateRow;}/*** 获取用户数量(根据用户名和角色筛选)** @param connection 数据库连接对象* @param queryUserName 查询的用户名* @param queryUserRole 查询的角色* @return 用户数量* @throws Exception 异常处理*/@Overridepublic int getUserCount(Connection connection, String queryUserName, Integer queryUserRole) throws Exception {// 初始化用户数量为0int userCount = 0;// 预编译SQL语句对象PreparedStatement preparedStatement;// 结果集对象ResultSet resultSet;// 存储查询参数的列表ArrayList<Object> list = new ArrayList<>();// 检查数据库连接是否不为空if (connection != null) {sb.delete(0, sb.length());sb.append("select count(1) as userCount from smbms_user u, smbms_role r ").append("where u.userRole = r.id ");// 如果查询用户名不为空,则添加用户名模糊查询条件if (queryUserName != null && !queryUserName.isEmpty()) {sb.append(" and u.userName like ? ");list.add("%" + queryUserName + "%");}// 如果查询角色不为空且大于0,则添加角色精确查询条件if (queryUserRole != null && queryUserRole > 0) {sb.append("and u.userRole = ? ");list.add(queryUserRole);}String sql = sb.toString();// 准备SQL语句执行preparedStatement = connection.prepareStatement(sql);// 将查询参数列表转换为数组形式Object[] params = list.toArray();// 执行查询并获取结果集resultSet = BaseDao.executeQuery(connection, sql, preparedStatement, params, null);// 如果结果集不为空,则从结果集中获取用户数量if (resultSet != null && resultSet.next()) {userCount = resultSet.getInt("userCount");} else {// 如果结果集为空,输出提示信息System.out.println("用户查询不到");}// 关闭数据库资源BaseDao.closeResource(connection, preparedStatement, resultSet);}// 返回用户数量return userCount;}/*** 分页查询用户集合** @param connection 数据库连接* @param userName 用户名字* @param userRole 角色id* @param currentPageNo 当前页码* @param pageSize 每页数量* @return 用户对象集合* @throws Exception 抛出SQL异常*/@Overridepublic List<User> getUserList(Connection connection, String userName, int userRole,int currentPageNo, int pageSize) throws Exception {List<User> users = new ArrayList<>();if (connection == null) {return users;}PreparedStatement preparedStatement;ResultSet rs;sb.delete(0, sb.length());sb.append("select u.*, r.roleName as userRoleName from smbms_user u, smbms_role r where " +"u.userRole = r.id");List<Object> list = new ArrayList<>();if (!StringUtils.isNullOrEmpty(userName)) {sb.append(" and u.userName like ?");list.add("%" + userName + "%");}if (userRole > 0) {sb.append(" and u.userRole = ?");list.add(userRole);}sb.append(" order by createDate DESC limit ?, ?");String sql = sb.toString();// 准备SQL语句执行preparedStatement = connection.prepareStatement(sql);currentPageNo = (currentPageNo - 1) * pageSize;list.add(currentPageNo);list.add(pageSize);Object[] params = list.toArray();rs = BaseDao.executeQuery(connection, sql, preparedStatement, params, null);while (rs.next()) {User user = getUserByResult(rs);
// user.setAge(user.getAge());user.setAge( DateUtils.getUserAge(user.getBirthday()));user.setUserRoleName(rs.getString("userRoleName"));users.add(user);}BaseDao.closeResource(connection, preparedStatement, rs);return users;}/*** 根据用户id获取用户信息** @param connection 数据库连接对象* @param id 用户id* @return 用户对象* @throws Exception 异常处理*/@Overridepublic User getUserById(Connection connection, int id) throws Exception {// 预编译SQL语句对象PreparedStatement preparedStatement;// 初始化一个空的用户对象User user = new User();// 检查数据库连接是否为空if (connection != null) {sb.delete(0, sb.length());// SQL查询语句,根据用户id查询用户信息sb.append("select * from smbms_user where id = ?");// 准备SQL语句preparedStatement = connection.prepareStatement(sb.toString());// 设置SQL语句中的参数,即用户idpreparedStatement.setInt(1, id);// 执行查询,获取结果集ResultSet rs = preparedStatement.executeQuery();if (rs != null && rs.next()) {// 从结果集中提取用户信息,封装到用户对象中user = getUserByResult(rs);}// 关闭数据库连接和资源,防止资源泄露BaseDao.closeResource(connection, preparedStatement, rs);}// 返回查询到的用户对象return user;}/*** 修改用户信息** @param connection 数据库连接对象* @param user 用户对象* @return 影响行数* @throws Exception 异常处理*/@Overridepublic int modify(Connection connection, User user) throws Exception {PreparedStatement preparedStatement;int updateRows = 0;sb.delete(0, sb.length());if (connection != null) {sb.append("update smbms_user set ");sb.append(" userName = ?, ");sb.append(" gender = ?, ");sb.append(" birthday = ?, ");sb.append(" phone = ?, ");sb.append(" address = ?, ");sb.append(" userRole = ?, ");sb.append(" modifyBy = ?, ");sb.append(" modifyDate = ? ");sb.append("where id = ?");preparedStatement = connection.prepareStatement(sb.toString());Object[] params = {user.getUserName(),user.getGender(),user.getBirthday(),user.getPhone(),user.getAddress(),user.getUserRole(),user.getModifyBy(),user.getModifyDate(),user.getId()};updateRows = BaseDao.executeUpdate(connection, sb.toString(), preparedStatement,params);BaseDao.closeResource(connection, preparedStatement, null);}return updateRows;}/*** 根据用户id删除用户** @param connection 数据库连接对象* @param delId 删除的用户id* @return 影响行数* @throws Exception 异常处理*/@Overridepublic int deleteUserById(Connection connection, Integer delId) throws Exception {PreparedStatement preparedStatement = null;int updateRows = 0;sb.delete(0, sb.length());if (connection != null) {sb.append("delete from smbms_user where id = ?");preparedStatement = connection.prepareStatement(sb.toString());preparedStatement.setInt(1, delId);updateRows = preparedStatement.executeUpdate();}BaseDao.closeResource(connection, preparedStatement, null);return updateRows;}/*** 添加用户** @param connection 数据库连接对象* @param user 用户对象* @return 影响行数* @throws Exception 异常处理*/@Overridepublic int add(Connection connection, User user) throws Exception {PreparedStatement preparedStatement;int updateRows = 0;// 初始化StringBuilder用于拼接SQL语句sb.delete(0, sb.length());// 检查数据库连接是否有效if (connection != null) {// 构建插入用户的SQL语句sb.append("insert into smbms_user ( ").append(" userCode, ").append(" userName, ").append(" userPassword, ").append(" gender, ").append(" birthday, ").append(" phone, ").append(" address, ").append(" userRole, ").append(" createBy, ").append( "createDate ").append(") values (?,?,?,?,?,?,?,?,?,?)");// 准备SQL语句preparedStatement = connection.prepareStatement(sb.toString());// 参数List< Object> params = new ArrayList<>();params.add(user.getUserCode());params.add(user.getUserName());params.add(user.getUserPassword());params.add(user.getGender());params.add(user.getBirthday());params.add(user.getPhone());params.add(user.getAddress());params.add(user.getUserRole());params.add(user.getCreatedBy());params.add(user.getCreateDate());//执行sql 返回执行结果(成功的语句数量)updateRows = BaseDao.executeUpdate(connection, sb.toString(), preparedStatement,params.toArray());//释放资源BaseDao.closeResource(null, preparedStatement, null);}// 返回影响的行数return updateRows;}/*** 检查用户编码是否存在** @param connection 数据库连接对象* @param userCode 用户编码* @return 用户对象*/@Overridepublic User selectUserCodeExist(Connection connection, String userCode) throws Exception {User user = null;PreparedStatement preparedStatement;sb.delete(0, sb.length());if (connection != null) {sb.append("select * from smbms_user where userCode = ?");preparedStatement = connection.prepareStatement(sb.toString());preparedStatement.setString(1, userCode);ResultSet rs = preparedStatement.executeQuery();while (rs.next()) {user = getUserByResult(rs);}BaseDao.closeResource(connection, preparedStatement, null);}return user;}/*** 根据数据库查询结果构建User对象* 此方法负责从ResultSet结果集中提取用户相关字段,并将这些字段映射到User对象中* 它简化了从数据库结果到对象的转换过程,提高了代码的可维护性和可重用性** @param rs 数据库查询结果集,包含构建User对象所需的所有字段信息* @return User 根据结果集构建的User对象,如果结果集为空,则返回null* @throws Exception 当从结果集提取数据时发生错误,例如字段不存在或数据类型不匹配*/private User getUserByResult(ResultSet rs) throws Exception {User user = new User();user.setId(rs.getInt("id"));user.setUserCode(rs.getString("userCode"));user.setUserName(rs.getString("userName"));user.setUserPassword(rs.getString("userPassword"));user.setGender(rs.getInt("gender"));user.setBirthday(rs.getDate("birthday"));user.setPhone(rs.getString("phone"));user.setAddress(rs.getString("address"));user.setUserRole(rs.getInt("userRole"));user.setCreatedBy(rs.getInt("createBy"));user.setCreateDate(rs.getTimestamp("createDate"));user.setModifyBy(rs.getInt("modifyBy"));user.setModifyDate(rs.getTimestamp("modifyDate"));return user;}
}
业务层sevice层的接口的实现
接口
package com.dashangms.service.user;import com.dashangms.pojo.User;
public interface UserService {/*** @param userCode 用户名* @param userPassword 密码* @return 用户对象*/public User login(String userCode, String userPassword);
}
实现相关的业务逻辑
package com.dashangms.service.user;import com.dashangms.dao.BaseDao;
import com.dashangms.dao.user.UserDao;
import com.dashangms.dao.user.UserDaoImpl;
import com.dashangms.pojo.User;import java.sql.Connection;
import java.sql.SQLException;public class UserServiceImpl implements UserService{private final UserDao userDao ;public UserServiceImpl(){userDao = new UserDaoImpl();}/*** @param userCode 用户名* @param userPassword 密码* @return 用户对象*/@Overridepublic User login(String userCode, String userPassword) {Connection conn = null;User user = null;try {conn = BaseDao.connection();user = userDao.getLoginUser(conn, userCode, userPassword);} catch (Exception e) {e.printStackTrace();}finally {BaseDao.closeConnection(conn);}return user;}}
编写servlet的业务逻辑
编写业务逻辑
package com.dashangms.servlet;import com.dashangms.pojo.User;
import com.dashangms.service.user.UserService;
import com.dashangms.service.user.UserServiceImpl;import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;public class LoginServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {String userCode = req.getParameter("userCode");String userPassword = req.getParameter("userPassword");UserService userService = new UserServiceImpl();User user = userService.login(userCode, userPassword);if (user != null) {req.getSession().setAttribute("user", user);resp.sendRedirect(req.getContextPath() + "/jsp/frame.jsp");} else {req.setAttribute("error", " 账号或密码错误!");req.getRequestDispatcher("/login.jsp").forward(req, resp);}}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {this.doGet(req, resp);}
}
映射接口路径
<!--注册Login servlet--><servlet><servlet-name>login</servlet-name><servlet-class>com.dashangms.servlet.LoginServlet</servlet-class></servlet><!--Login servlet请求路径--><servlet-mapping><servlet-name>login</servlet-name><url-pattern>/login</url-pattern></servlet-mapping>
登出、注册、注销、修改
登出属于断开登录,操作session就可以解决
应用更改数据库的处理模式,add,delete,modify都是属于事务处理操作
登出操作的实现逻辑及方式
清楚session就可以,不再保存登录记录
package com.dashangms.servlet.user;import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;public class LogoutServlet extends HttpServlet {@Overridepublic void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {// 移除session 中的用户信息request.getSession().removeAttribute("user");// 跳转到登录页面response.sendRedirect(request.getContextPath() + "/jsp/login.jsp");}Overridepublic void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {this.doGet(request, response);}
}
<!--注册Logout servlet--><servlet><servlet-name>logout</servlet-name><servlet-class>com.dashangms.servlet.user.LogoutServlet</servlet-class></servlet><!--Logout servlet请求路径--><servlet-mapping><servlet-name>logout</servlet-name><url-pattern>/logout</url-pattern></servlet-mapping>
防止用户登出后可以继续访问
- 思路:页面登出时先走login拦截器,如果session清空就说明已退出
package com.dashangms.filter;import com.common.Constants;import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;public class LoginFilter extends HttpFilter {/*** 执行过滤操作** @param request Servlet请求,用于获取HTTP请求信息* @param response Servlet响应,用于向客户端发送数据* @param chain 过滤链,用于将请求传递给下一个过滤器或目标资源* @throws IOException 如果在执行过程中发生I/O错误* @throws ServletException 如果在执行过程中发生Servlet错误*/@Overridepublic void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException{// 将ServletRequest和ServletResponse转换为HttpServletRequest和HttpServletResponse// 以使用它们提供的高级功能和方法HttpServletRequest httpServletRequest = (HttpServletRequest) request;HttpServletResponse httpServletResponse = (HttpServletResponse) response;// 检查用户会话中是否存在用户信息// 如果不存在,说明用户未登录或会话已过期if (httpServletRequest.getSession().getAttribute(Constants.USER_SESSION) == null) {// 重定向用户到错误页面// 这里假设错误页面为"/error.jsp",实际路径应根据项目具体结构设置httpServletResponse.sendRedirect(httpServletRequest.getContextPath() + "/error.jsp");} else {// 如果用户会话中存在用户信息,继续执行过滤链// 这允许请求继续传递到目标资源或下一个过滤器chain.doFilter(request, response);}}@Overridepublic void init() throws ServletException {super.init();}@Overridepublic void destroy() {super.destroy();}
}
- 登出后访问任意页面走过滤器处理
<!-- 判断用户是否登录的过滤器--><filter><filter-name>LoginFilter</filter-name><filter-class>com.csnz.filter.LoginFilter</filter-class></filter><filter-mapping><filter-name>LoginFilter</filter-name><url-pattern>/jsp/*</url-pattern></filter-mapping>
修改密码功能实现
导入jsp
<li><a href=${pageContext.request.contextPath}"/jsp/pwdmodify.jsp">密码修改</a></li>
实现Dao层数据接口
- 在Dao写一个接口
int updatePwd(Connection connection, Integer id, String newPwd) throws Exception;
- 实现这个接口
/*** 更新用户密码** @param connection 数据库连接对象* @param id 用户id* @param newPwd 新密码* @return 影响行数* @throws Exception 异常处理*/@Overridepublic int updatePwd(Connection connection, Integer id, String newPwd) throws Exception {// 初始化影响行数为0int updateRow = 0;// 检查数据库连接是否为空if (connection != null){// 预编译SQL语句以提高性能和安全性PreparedStatement preparedStatement = null;String sql = "update smbms_user set userPassword = ? where id = ?";preparedStatement = connection.prepareStatement(sql);// 设置SQL语句参数preparedStatement.setString(1, newPwd);preparedStatement.setInt(2, id);// 执行更新操作并获取影响行数updateRow = preparedStatement.executeUpdate();// 关闭数据库连接和预编译语句资源BaseDao.closeResource(connection, preparedStatement, null);}// 返回影响行数return updateRow;}
实现Service层业务接口
- 在Service上写一个接口
/*** 修改密码* @param id 用户id* @param newPwd 新密码* @return 修改成功 flag*/public boolean updatePwd(Integer id, String newPwd);
- 实现这个Service
/*** 修改密码** @param id 用户id* @param newPwd 新密码* @return 修改成功 flag*/@Overridepublic boolean updatePwd(Integer id, String newPwd) {Connection conn = null;boolean flag = false;try {conn = BaseDao.connection();if (userDao.updatePwd(conn, id, newPwd) > 0){flag = true;}} catch (Exception e) {e.printStackTrace();} finally {BaseDao.closeConnection(conn);}return flag;}
注册Servlet
- 多个按钮会在同一个Servlet的中调用不同的方法;
- 相关密码的check逻辑:
- 密码不能为空
- 密码与旧密码不能相同
- 密码输入要合法化
- 密码修改成功与否都会返回原页面。有msg显示。
package com.dashangms.servlet.user;import com.dashangms.pojo.User;
import com.dashangms.service.user.UserService;
import com.dashangms.service.user.UserServiceImpl;import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;public class UserServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {String method = req.getParameter("method");if ("savePassword".equals(method)) {savePassword(req, resp);}}@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {this.doGet(req, resp);}/*** 保存用户新密码** @param req HTTP请求对象,用于获取请求参数和进行页面转发* @param resp HTTP响应对象,用于进行页面转发* @throws ServletException 如果Servlet操作出错* @throws IOException 如果输入输出操作出错*/private void savePassword(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// 获取用户ID和新密码String id = req.getParameter("id");String newPwd = req.getParameter("newPwd");Object object = req.getSession().getAttribute("user");User user = (User) object;// 创建UserService对象UserService userService = new UserServiceImpl();if (user.getUserPassword().isEmpty()) {req.getSession().setAttribute("message", "密码不能为空!");} else if (user.getUserPassword().equals(newPwd)) {req.getSession().setAttribute("message", "新密码不能与旧密码相同!");} else {// 调用UserService的updatePwd方法更新用户密码if (userService.updatePwd(Integer.parseInt(id), newPwd)) {req.getSession().setAttribute("message", "密码修改成功!请使用新密码重新登陆");// 移除用户会话中的用户信息,表示用户已经注销req.getSession().removeAttribute("user");} else {// 如果密码更新失败,转发到错误页面req.getSession().setAttribute("message", "密码更新失败!");}}// 如果密码更新成功,转发到密码修改页面req.getRequestDispatcher("/pwdmodify.jsp").forward(req, resp);}
}
- 注册Servlet
<servlet><servlet-name>UserServlet</servlet-name><servlet-class>com.dashangms.servlet.user.UserServlet</servlet-class></servlet><servlet-mapping><servlet-name>UserServlet</servlet-name><url-pattern>/jsp/user.do</url-pattern></servlet-mapping>
注册和注销 用户的方式(优化)
同上 改善点
导入jsp
可以共同使用同一个页面,根据前面页面传的值使用hidden确定显示哪部分内容;
实现Dao层的数据逻辑
- 插入新用户 insert
- 注销(删除)新用户 update (逻辑删除)
实现Service逻辑
- 插入新用户 insert
- 使用前先判断是否有同样的账号,判断一致性插入
- 注销(删除)新用户 update (逻辑删除)
- 停用功能,:停用和启用相对应,不会删除数据
- 删除功能
- 物理删除?
- 逻辑删除?
注册Servlet
同样在UserServlet中调用其他的逻辑,主要点 在jsp中确定实现
不需要再新注册Servlet来实现
用户管理模块
用户管理模块需要包含的功能需要有添加用户、删除用户、查询用户、修改用户;显示时会进行表单显示,有分页功能,页码计算功能。
前期准备
共同工具类
翻页使用的对象工具类,计算页数方式如下:
每次显示的页数 = 总件数 % 单页显示的件数 == 0 ? 总件数 / 单页显示的件数 :(总件数 / 单页显示的件数)+1;
package com.common.utils;public class PageSupport {private int pageIndex = 1; // 当前页码private int pageSize; // 总页数private int totalCount; // 总记录数private int totalPageCount; // 每页显示的记录数public int getPageIndex() {return pageIndex;}public void setPageIndex(int pageIndex) {if (pageIndex > 0) {this.pageIndex = pageIndex;}}public int getPageSize() {return pageSize;}public void setPageSize(int pageSize) {if (pageSize > 0) {this.pageSize = pageSize;}}public int getTotalCount() {return totalCount;}public void setTotalCount(int totalCount) {if (totalCount > 0) {this.totalCount = totalCount;setByPageNo(totalCount);}}public int getTotalPageCount() {return totalPageCount;}public void setTotalPageCount(int totalPageCount) {this.totalPageCount = totalPageCount;}/*** 根据总记录数设置总页数* 此方法用于计算分页时的总页数,基于当前的每页记录数(pageSize)** @param totalCount 总记录数,即需要分页处理的数据总量*/private void setByPageNo(int totalCount) {// 计算总页数:如果总记录数除以每页记录数的余数为0,则总页数为总记录数除以每页记录数;// 否则,总页数为总记录数除以每页记录数加1this.totalPageCount = totalCount % pageSize == 0 ? totalCount / pageSize :totalCount / pageSize + 1;}}
导入前端代码
导入前端页面和相关js,跳转页面的时候及翻页的时候使用。
获取用户数量
需要为查询数据做好基础,涉嫌到数据统计。
UserDao
通过用户名称或角色查询获取用户数量,设计的功能模块有关下拉选择查询总数。
- UserDao
/*** 获取用户数量(根据用户名和角色筛选)** @param connection 数据库连接对象* @param queryUserName 查询的用户名* @param queryUserRole 查询的角色* @return 用户数量* @throws Exception 异常处理*/int getUserCount(Connection connection, String queryUserName, Integer queryUserRole) throws Exception;
- UserDaoImpl
/*** 获取用户数量(根据用户名和角色筛选)** @param connection 数据库连接对象* @param queryUserName 查询的用户名* @param queryUserRole 查询的角色* @return 用户数量* @throws Exception 异常处理*/@Overridepublic int getUserCount(Connection connection, String queryUserName, Integer queryUserRole) throws Exception {// 初始化用户数量为0int userCount = 0;// 预编译SQL语句对象PreparedStatement preparedStatement = null;// 结果集对象ResultSet resultSet = null;// 存储查询参数的列表ArrayList<Object> list = new ArrayList<>();// 检查数据库连接是否不为空if (connection != null) {// 构建基础SQL查询语句String sql = "select count(1) as userCount from smbms_user u, smbms_role r where u" +".userRole = r.id ";// 如果查询用户名不为空,则添加用户名模糊查询条件if (queryUserName != null && !queryUserName.isEmpty()) {sql += "and u.userName like ? ";list.add("%" + queryUserName + "%");}// 如果查询角色不为空且大于0,则添加角色精确查询条件if (queryUserRole != null && queryUserRole > 0) {sql += "and u.userRole = ? ";list.add(queryUserRole);}// 准备SQL语句执行preparedStatement = connection.prepareStatement(sql);// 将查询参数列表转换为数组形式Object[] params = list.toArray();// 执行查询并获取结果集resultSet = BaseDao.executeQuery(connection, sql, preparedStatement, params, resultSet);// 如果结果集不为空,则从结果集中获取用户数量if (resultSet != null) {userCount = resultSet.getInt("userCount");} else {// 如果结果集为空,输出提示信息System.out.println("用户查询不到");}// 关闭数据库资源BaseDao.closeResource(connection, preparedStatement, resultSet);}// 返回用户数量return userCount;}
UserService
调用Dao层的sql处理,如果出现问题及时抛出异常,之后在进行关闭连接。
- UserService
public int getUserCount(String queryUserName, Integer queryUserRole);
- UserServiceImpl
/*** 获取用户数量* 根据用户名和用户角色查询用户数量** @param queryUserName 查询的用户名,如果为null,则不根据用户名进行筛选* @param queryUserRole 查询的用户角色,如果为null,则不根据用户角色进行筛选* @return 返回查询到的用户数量*/@Overridepublic int getUserCount(String queryUserName, Integer queryUserRole) {// 定义数据库连接对象Connection conn = null;// 初始化用户数量为0int userCouts = 0;try {// 获取数据库连接conn = BaseDao.connection();// 调用UserDao的getUserCount方法查询用户数量userCouts = userDao.getUserCount(conn, queryUserName, queryUserRole);} catch (Exception e) {// 打印异常信息e.printStackTrace();} finally {// 关闭数据库资源BaseDao.closeResource(conn, null, null);}// 返回查询到的用户数量return userCouts;}
获取用户列表
根据查询条件查询需要的数据,根据翻页页数计算需要显示的数据是那些条;
UserDao
使用order by和 limit 关键字 应用;
- userDao
List<User> getUserList(Connection connection, String userName, int userRole, int currentPageNo, int pageSize) throws Exception;
- userDaoImpl
/*** 分页查询用户集合* @param connection 数据库连接* @param userName 用户名字* @param userRole 角色id* @param currentPageNo 当前页码* @param pageSize 每页数量* @return 用户对象集合* @throws Exception 抛出SQL异常*/@Overridepublic List<User> getUserList(Connection connection, String userName, int userRole, int currentPageNo, int pageSize) throws Exception {List<User> users = new ArrayList<>();if (connection == null) {return users;}PreparedStatement preparedStatement = null;ResultSet rs = null;StringBuilder sql = new StringBuilder();sql.append("select u.*, r.roleName as userRoleName from smbms_user u, smbms_role r where u.userRole = r.id");List<Object> list = new ArrayList<>();if (!StringUtils.isNullOrEmpty(userName)) {sql.append(" and u.userName like ?");list.add("%" + userName + "%");}if (userRole > 0) {sql.append(" and u.userRole = ?");list.add(userRole);}sql.append(" order by creationDate DESC limit ?, ?");// 准备SQL语句执行preparedStatement = connection.prepareStatement(sql.toString());currentPageNo = (currentPageNo - 1) * pageSize;list.add(currentPageNo);list.add(pageSize);Object[] params = list.toArray();rs = BaseDao.executeQuery(connection, sql.toString(),preparedStatement, params, rs);while (rs.next()) {User user = getUserByResult(rs);user.setUserRoleName(rs.getString("userRoleName"));users.add(user);}BaseDao.closeResource(connection,preparedStatement, rs);return users;}
UserService
- UserService
List<User> getUserList(String queryUserName, int queryUserRole, int currentPageNo,int pageSize);
- UserServiceImpl
/*** @param queryUserName* @param queryUserRole* @param currentPageNo* @param pageSize* @return*/@Overridepublic List<User> getUserList(String queryUserName, int queryUserRole, int currentPageNo,int pageSize) {Connection conn = null;List<User> userList = null;try {conn = BaseDao.connection();userList = userDao.getUserList(conn, queryUserName, queryUserRole, currentPageNo,pageSize);} catch (Exception e) {e.printStackTrace();} finally {BaseDao.closeResource(conn, null, null);}return userList;}
获取用户角色 列表
查询数据库中的角色
RoleDao
- RoleDao
package com.dashangms.dao.role;import com.dashangms.dao.BaseDao;
import com.dashangms.pojo.Role;import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;public interface RoleDao {List<Role> getRoleList(Connection connection) throws SQLException;
}
- RoleDaoImpl
package com.dashangms.dao.role;import com.dashangms.dao.BaseDao;
import com.dashangms.pojo.Role;import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;public class RoleDaoImpl implements RoleDao {/*** 获取角色列表** @param connection 数据库连接对象,用于执行SQL查询* @return 返回一个Role对象列表,包含从数据库查询到的所有角色信息* @throws SQLException 如果在执行数据库操作时发生错误*/@Overridepublic List<Role> getRoleList(Connection connection) throws SQLException {// 创建一个ArrayList用于存储Role对象ArrayList<Role> roleList = new ArrayList<Role>();// 定义ResultSet对象用于存储查询结果ResultSet resultSet = null;// 检查传入的数据库连接对象是否不为空if (connection != null) {// 定义SQL查询语句,用于从smbms_role表中查询所有数据String sql = "select * from smbms_role";// 定义一个空的参数数组,用于执行带有参数的SQL语句(此处无参数)Object[] params = {};// 执行SQL查询,并将结果存储在resultSet中resultSet = BaseDao.executeQuery(connection, sql, null, params, resultSet);// 遍历查询结果,将每条记录封装成Role对象while (resultSet.next()) {Role role = new Role();// 从结果集中获取id、roleCode、roleName等字段,并设置到Role对象中role.setId(resultSet.getInt("id"));role.setRoleCode(resultSet.getString("roleCode"));role.setRoleName(resultSet.getString("roleName"));role.setCreateBy(resultSet.getInt("createBy"));role.setCreateDate(resultSet.getTimestamp("createDate"));role.setModifyBy(resultSet.getInt("modifyBy"));role.setModifyDate(resultSet.getTimestamp("modifyDate"));// 将封装好的Role对象添加到列表中roleList.add(role);}// 关闭数据库资源,包括连接、声明和结果集BaseDao.closeResource(connection, null, resultSet);}// 返回角色列表return roleList;}}
RoleService
- RoleService
package com.dashangms.service.role;import com.dashangms.pojo.Role;import java.util.List;public interface RoleService {List<Role> getRoleList();
}
- RoleServiceImpl
package com.dashangms.service.role;import com.dashangms.dao.BaseDao;
import com.dashangms.dao.role.RoleDaoImpl;
import com.dashangms.pojo.Role;
import com.dashangms.dao.role.RoleDao;import java.sql.Connection;
import java.util.ArrayList;
import java.util.List;public class RoleServiceImpl implements RoleService{private RoleDao roleDao;public RoleServiceImpl() {roleDao = new RoleDaoImpl();}/***/@Overridepublic List<Role> getRoleList() {Connection connection = null;List<Role> roleList = null;try {connection = BaseDao.connection();roleList = roleDao.getRoleList(connection);}catch (Exception e){e.printStackTrace();}finally {BaseDao.closeConnection(connection);}return roleList;}
}
编写查询用户的Servlet
编写查询的servlet,在画面初次加载或者查询的时候调用该方法,查询数据,显示分页,避免非空场景。
doGet方法
if ("query".equals(method)) {query(req, resp);
}
query方法
/*** 处理用户查询请求的方法* 该方法根据用户输入的查询条件(用户名和用户角色)以及分页信息(当前页码),* 查询并返回用户列表同时将结果存储在HttpServletRequest对象中,* 以便在JSP页面中显示** @param req 用于获取请求参数和设置属性的HttpServletRequest对象* @param resp 用于响应的HttpServletResponse对象*/private void query(HttpServletRequest req, HttpServletResponse resp) {// 获取查询条件:用户名和用户角色String queryUserName = req.getParameter("queryUserName");String queryUserRoleTemp = req.getParameter("queryUserRole");String pageIndex = req.getParameter("pageIndex");int queryUserRole = 0; // 默认用户角色// 创建UserService实例UserService userService = new UserServiceImpl();List<User> userList;// 默认分页设置int currentPageNo = 1;int pageSize = 5;// 处理查询条件,确保空值安全queryUserName = queryUserName == null ? "" : queryUserName;queryUserRole = queryUserRoleTemp.isEmpty() ? queryUserRole :Integer.parseInt(queryUserRoleTemp);currentPageNo = pageIndex == null ? currentPageNo : Integer.parseInt(pageIndex);// 获取用户总数,用于分页int totalCount = userService.getUserCount(queryUserName, queryUserRole);// 创建并配置PageSupport对象PageSupport pageSupport = new PageSupport();pageSupport.setPageIndex(currentPageNo);pageSupport.setPageSize(pageSize);pageSupport.setTotalCount(totalCount);// 计算总页数int totalPageCount = pageSupport.getTotalPageCount();// 校验当前页码if (currentPageNo < 1) {currentPageNo = 1;} else {if (currentPageNo > totalPageCount) {currentPageNo = totalPageCount;}}// 根据查询条件和分页信息获取用户列表userList = userService.getUserList(queryUserName, queryUserRole, currentPageNo, pageSize);// 将用户列表和其他信息存储在请求对象中req.setAttribute("userList", userList);// 创建RoleService实例并获取角色列表RoleService roleService = new RoleServiceImpl();List<Role> roleList = roleService.getRoleList();// 将角色列表和其他信息存储在请求对象中req.setAttribute("roleList", roleList);req.setAttribute("totalCount", totalCount);req.setAttribute("currentPageNo", currentPageNo);req.setAttribute("totalPageCount", totalPageCount);req.setAttribute("queryUserName", queryUserName);req.setAttribute("queryUserRole", queryUserRole);// 转发到userlist.jsp页面显示结果try {req.getRequestDispatcher("/userlist.jsp").forward(req, resp);} catch (ServletException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();}}
添加用户子模块
添加用户,查找用户是否存在;需要考虑到添加失败后事务回滚
导入jsp请求按钮
UserDao逻辑
- UserDao
//用户管理模块中的 子模块—— 添加用户public int addUser(Connection conn,User user)throws SQLException;
- UserDaoImpl
//用户管理模块中的 子模块—— 添加用户public int addUser(Connection conn,User user)throws SQLException{{PreparedStatement preparedStatement;int updateRows = 0;if(connection != null){String sql = "insert into smbms_user (userCode,userName,userPassword,gender,birthday,phone,address,userRole,createdBy,creationDate)values(?,?,?,?,?,?,?,?,?,?)";Object[] params ={user.getUserRole(),user.getUserName(),user.getUserPassword(),user.getGender(),user.getBirthday(),user.getPhone(),user.getAddress(),user.getUserRole(),user.getCreatedBy(),user.getCreateDate()};preparedStatement = connection.prepareStatement(sql);//执行sql 返回执行结果(成功的语句数量)updateRows= BaseDao.executeUpdate(connection,sql,preparedStatement,params);//释放资源BaseDao.closeResource(null,preparedStatement,null);}return updateRows;}
UserService逻辑
- UserService
//用户管理模块中的 子模块—— 添加用户boolean addUser(User user);
- UserServiceImpl
/*** @param user* @return*/@Overridepublic boolean addUser(User user) throws SQLException {Connection conn = null;boolean flag = false;try {//获取数据库连接conn = BaseDao.connection();//开启JDBC事务管理conn.setAutoCommit(false);//Service层调用dao层的方法添加用户int updateRows = userDao.add(conn, user);conn.commit();if(updateRows > 0){flag = true;}} catch (Exception e) {e.printStackTrace();if (conn != null) {conn.rollback();}}finally {//释放连接BaseDao.closeResource(conn,null,null);}return flag;}
删除用户子模块
导入jsp请求按钮
UserDao逻辑
- UserDao
int deleteUserById(Connection connection, Integer delId) throws Exception;
- UserDaoImpl
/*** 根据用户id删除用户** @param connection 数据库连接对象* @param delId 删除的用户id* @return 影响行数* @throws Exception 异常处理*/@Overridepublic int deleteUserById(Connection connection, Integer delId) throws Exception {PreparedStatement preparedStatement = null;int updateRows = 0;if(connection != null){String sql = "delete from smbms_user where id = ?";preparedStatement = connection.prepareStatement(sql);preparedStatement.setInt(1, delId);updateRows = preparedStatement.executeUpdate();}BaseDao.closeResource(connection, preparedStatement, null);return updateRows;}
UserService逻辑
- UserService
int deleteUser(Integer delId);
- UserServiceImpl
/*** @param delId* @return*/@Overridepublic int deleteUser(Integer delId) {Connection conn = null;int delectedRows = 0;try {conn = BaseDao.connection();delectedRows = userDao.deleteUserById(conn, delId);} catch (Exception e) {e.printStackTrace();} finally {BaseDao.closeResource(conn, null, null);}return delectedRows;}
修改用户子模块
导入jsp请求按钮,检查
UserDao逻辑
- UserDao
int modify(Connection connection, User user) throws Exception;
- UserDaoImpl
/*** 修改用户信息** @param connection 数据库连接对象* @param user 用户对象* @return 影响行数* @throws Exception 异常处理*/@Overridepublic int modify(Connection connection, User user) throws Exception {PreparedStatement preparedStatement = null;int updateRows = 0;if(connection != null){String sql = "update smbms_user " +" set userName = ?, " +" gender = ?, " +" birthday = ?, " +" phone = ?, " +" address = ?, " +" userRole = ?, " +" modifyBy = ?, " +" modifyDate = ? " +"where " +" id = ?";Object[] params = {user.getUserName(),user.getGender(),user.getBirthday(),user.getPhone(),user.getAddress(),user.getUserRole(),user.getModifyBy(),user.getModifyDate(),user.getId()};preparedStatement = connection.prepareStatement(sql);updateRows = BaseDao.executeUpdate(connection, sql, preparedStatement, params);BaseDao.closeResource(connection, preparedStatement, null);}return updateRows;}
UserService逻辑
- UserService
int modifyUser(User user);
- UserServiceImp
/*** @param user* @return*/@Overridepublic int modifyUser(User user) {Connection conn = null;int updateRows = 0;try {conn = BaseDao.connection();updateRows = userDao.modify(conn, user);conn.commit();} catch (Exception e) {e.printStackTrace();} finally {BaseDao.closeResource(conn, null, null);}return updateRows;}
查询用户子模块
导入jsp请求按钮,检查
思路:
- 跟前面查询数据走同一个Dao的数据查询逻辑,在service/servlet层对数据进行区分?
- 通过画面hidden项传递?
- 通过页面id(主键查询)传递?
Servlet
public class UserServlet extends HttpServlet {@Overrideprotected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {String method = req.getParameter("method");if ("savePassword".equals(method)) {savePassword(req, resp);} else if ("query".equals(method)) {query(req, resp);} else if ("modify".equals(method)) {modify(req, resp);} else if ("delete".equals(method)) {delete(req, resp);} else if ("add".equals(method)) {try {add(req, resp);} catch (SQLException e) {throw new RuntimeException(e);}} else if ("viewUser".equals(method)) {viewUser(req, resp);}}/*** 该方法用于处理用户信息查看请求* 它从HTTP请求中提取用户ID,调用服务层方法获取用户信息,* 并将用户信息发送到前端页面进行展示** @param req HTTP请求对象,用于获取请求参数和设置属性* @param resp HTTP响应对象,用于跳转到其他页面* @throws ServletException 如果Servlet操作失败* @throws IOException 如果输入输出操作失败*/private void viewUser(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {//从前端获取 要查询用户 的idString id = req.getParameter("id");int userId = 0;try {//将获取到的字符串id转换为整型,以便后续使用userId = Integer.parseInt(id);} catch (Exception e) {//异常处理:打印错误信息,如果转换失败e.printStackTrace();}//调用 根据id查询用户信息的方法UserServiceImpl userService = new UserServiceImpl();User user = userService.getUserById(userId);//将此user发送到展示前端 的页面进行展示req.setAttribute("user", user);//跳转到前端 的展示页面req.getRequestDispatcher("userview.jsp").forward(req, resp);}
}
UserService逻辑 :getUserById
- UserService
User getUserById(int userId);
- UserServiceImpl
/*** @param userId* @return*/@Overridepublic User getUserById(int userId) {Connection conn = null;User user = null;try {conn = BaseDao.connection();user = userDao.getUserById(conn, userId);} catch (Exception e) {e.printStackTrace();} finally {BaseDao.closeResource(conn, null, null);}return user;}
UserDao
- UserDao
/*** 根据用户id获取用户信息** @param connection 数据库连接对象* @param id 用户id* @return 用户对象* @throws Exception 异常处理*/
User getUserById(Connection connection, int id) throws Exception;
- UserDaoImpl :主键查询
/*** 根据用户id获取用户信息** @param connection 数据库连接对象* @param id 用户id 主键* @return 用户对象* @throws Exception 异常处理*/@Overridepublic User getUserById(Connection connection, int id) throws Exception {PreparedStatement preparedStatement = null;ResultSet rs = null;List<User> users = new ArrayList<>();User user = new User();if(connection != null){String sql = "select * from smbms_user where id = ?";preparedStatement = connection.prepareStatement(sql);// Object[] parmes = new Object[1];
// parmes[0] = Integer.parseInt(id);preparedStatement.setInt(1, id);
// rs = BaseDao.executeQuery(connection, sql, preparedStatement, parmes, rs);rs = preparedStatement.executeQuery();// while (rs.next()){user = getUserByResult(rs);
// users.add(user);
// }BaseDao.closeResource(connection, preparedStatement, rs);}return user;}
供应商管理
前期准备
- 创建供应商 provider 的servlet
- 注册 provider 的servlet
- 创建相关的Dao,Service,javaBean等
- 导入相关的jsp
增加供应商
addProvider
PrivodeDao
- PrivodeDao
int addProvider(Provider provider);
- PrivodeDaoImpl
/*** 向数据库中添加供应商信息** @param connection 数据库连接对象,用于执行SQL语句* @param provider 供应商对象,包含要添加的供应商的信息* @return 返回添加的行数,用于确认是否成功添加供应商* @throws Exception 如果在添加过程中发生错误,则抛出异常*/@Overridepublic int addProvider(Connection connection, Provider provider) throws Exception {// 初始化添加行数为0int addRows = 0;// 预编译的SQL语句对象PreparedStatement preparedStatement;// 检查数据库连接是否为空if (connection != null) {// 准备插入供应商信息的SQL语句String sql = "insert into smbms_provider (" +"proCode, " +"proName, " +"proDesc, " +"proContact, " +"proPhone, " +"proAddress, " +"proFax, " +"createBy, " +"createDate) " +" values(?,?,?,?,?,?,?,?,?)";// 初始化参数数组,用于存放SQL语句中的参数值Object[] params = new Object[9];// 设置SQL语句中的参数值params[0] = provider.getProCode();params[1] = provider.getProName();params[2] = provider.getProDesc();params[3] = provider.getProContact();params[4] = provider.getProPhone();params[5] = provider.getProAddress();params[6] = provider.getProFax();params[7] = provider.getCreateBy();params[8] = provider.getCreateDate();// 准备SQL语句执行对象preparedStatement = connection.prepareStatement(sql);// 执行插入操作,并返回添加的行数addRows = BaseDao.executeUpdate(connection, sql, preparedStatement, params);}// 返回添加的行数return addRows;}
ProviderService
- ProviderService
boolean addProvider(Provider provider) throws SQLException, Exception;
- ProviderServiceImpl
/*** 添加一个新的供应商到系统中。* <p>* 此方法用于将提供的供应商对象添加到数据库中。它涉及数据库操作和事务管理,* 根据操作的成功或失败提交或回滚事务。** @param provider 要添加的供应商对象,包含供应商的相关信息。* @return 返回一个布尔值,指示添加操作是否成功。true 表示成功,false 表示失败。* @throws SQLException 如果发生数据库访问错误,该方法将抛出一个 SQLException。*/@Overridepublic boolean addProvider(Provider provider) throws SQLException {// 初始化数据库连接对象和方法返回值Connection conn = null;boolean flag = false;try {// 获取数据库连接并准备事务conn = BaseDao.connection();conn.setAutoCommit(false);// 调用数据访问对象方法添加供应商,并尝试提交事务int addRows = providerDao.addProvider(conn, provider);conn.commit();// 根据受影响的行数判断添加是否成功if (addRows > 0) {flag = true;}} catch (SQLException e) {// 遇到 SQLException 时回滚事务conn.rollback();} catch (Exception e) {// 对于其他异常,转换为 RuntimeException 并重新抛出throw new RuntimeException(e);} finally {// 在 finally 块中关闭数据库资源以确保执行BaseDao.closeResource(conn, null, null);}// 返回添加供应商的结果return flag;}
ProviderServlet
/*** 处理HTTP Post请求的方法* 根据请求参数中的method字段值,决定执行相应的操作** @param req HttpServletRequest对象,用于获取请求参数* @param resp HttpServletResponse对象,用于向客户端发送数据* @throws ServletException 如果Servlet操作失败* @throws IOException 如果发生输入输出异常*/@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// 获取请求参数中的method值,如果为空则默认为空字符串String method = req.getParameter("method") == null ? "" : req.getParameter("method");// 根据method值调用对应的方法执行操作switch (method) {case "add":addProvider(req, resp);break;}}/*** 添加供应商信息* <p>* 此方法从HTTP请求中提取供应商信息,并将其添加到数据库中* 如果添加成功,将用户重定向到供应商查询页面;如果添加失败,则重定向回添加供应商页面,并显示错误信息** @param req HTTP请求对象,用于获取请求参数和会话信息* @param resp HTTP响应对象,用于重定向用户* @throws ServletException 如果Servlet操作失败* @throws IOException 如果输入/输出操作失败*/private void addProvider(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// 获取当前登录用户信息User user = (User) req.getSession().getAttribute(Constants.USER_SESSION);// 创建一个新的供应商对象,并从请求中设置其属性Provider provider = new Provider();provider.setProCode(req.getParameter("proCode"));provider.setProName(req.getParameter("proName"));provider.setProDesc(req.getParameter("proDesc"));provider.setProContact(req.getParameter("proContact"));provider.setProPhone(req.getParameter("proPhone"));provider.setProAddress(req.getParameter("proAddress"));provider.setProFax(req.getParameter("proFax"));// 设置创建者和修改者为当前用户provider.setCreateBy(user.getId());provider.setModifyBy(user.getId());// 设置创建和修改日期为当前日期provider.setCreateDate(new Date());provider.setModifyDate(new Date());// 尝试将供应商信息添加到数据库中try {if (providerService.addProvider(provider)) {// 如果添加成功,设置成功消息并重定向到供应商查询页面req.getSession().setAttribute("message", "添加成功!");resp.sendRedirect(req.getContextPath() + "/provider?method=query");} else {// 如果添加失败,设置错误消息并重定向回添加供应商页面req.getSession().setAttribute("message", "添加失败!");resp.sendRedirect(req.getContextPath() + "/jsp/provideradd.jsp");}} catch (Exception e) {// 如果发生异常,抛出运行时异常throw new RuntimeException(e);}// 无论上述操作结果如何,最终将用户重定向回添加供应商页面
// req.getRequestDispatcher("/jsp/provideradd.jsp").forward(req, resp);}
删除供应商
deleteProvider
ProviderDao
- ProviderDao
int deleteProvider(Connection connection, int id) throws SQLException;
- ProviderDaoImpl
/*** 根据给定的ID删除供应商信息** @param connection 数据库连接对象,用于执行SQL语句* @param id 需要删除的供应商的ID* @return 返回删除的行数,表示删除成功的记录数* @throws SQLException 如果执行SQL语句时发生错误*/@Overridepublic int deleteProvider(Connection connection, int id) throws SQLException {int deleteRows = 0;PreparedStatement preparedStatement;if (connection != null) {// 定义删除供应商的SQL语句String sql = "delete from smbms_provider where id=?";// 准备SQL语句preparedStatement = connection.prepareStatement(sql);// 设置SQL语句中的参数preparedStatement.setInt(1, id);// 执行更新操作deleteRows = preparedStatement.executeUpdate();// 关闭资源BaseDao.closeResource(connection, preparedStatement, null);}// 返回删除的行数return deleteRows;}
ProviderService
- ProviderService
void deleteProvider(int id);
- ProviderServiceImpl
/*** 根据供应商ID删除供应商信息* * @param id 供应商的ID,用于标识要删除的供应商* @return 返回删除的行数,用于确认是否成功删除供应商信息*/
@Override
public int deleteProvider(int id) {// 初始化删除行数为0int deleteRows = 0;// 声明数据库连接对象Connection conn = null;try {// 获取数据库连接conn = BaseDao.connection();// 调用供应商数据访问对象的删除方法,执行删除操作deleteRows = providerDao.deleteProvider(conn, id);} catch (SQLException e) {// 如果捕获到SQL异常,抛出运行时异常throw new RuntimeException(e);} finally {// 关闭数据库资源,确保数据库连接被释放BaseDao.closeResource(conn, null, null);}// 返回删除的行数return deleteRows;
}
ProviderServlet
/*** 处理HTTP Post请求的方法* 根据请求参数中的method字段值,决定执行相应的操作** @param req HttpServletRequest对象,用于获取请求参数* @param resp HttpServletResponse对象,用于向客户端发送数据* @throws ServletException 如果Servlet操作失败* @throws IOException 如果发生输入输出异常*/@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// 获取请求参数中的method值,如果为空则默认为空字符串String method = req.getParameter("method") == null ? "" : req.getParameter("method");// 根据method值调用对应的方法执行操作switch (method) {case "add":addProvider(req, resp);break;case "deleteProvider":deleteProvider(req, resp);break;}}
更改供应商信息
modifyProvider
ProviderDao
- ProviderDao
int updateProvider(Connection connection, Provider provider) throws SQLException;
- ProviderDaoImpl
/*** 更新供应商信息** @param connection 数据库连接对象,用于执行SQL语句* @param provider 待更新的供应商对象,包含新的供应商信息* @return 返回更新影响的行数,用于判断更新操作是否成功* @throws SQLException 如果执行SQL语句时发生错误*/@Overridepublic int updateProvider(Connection connection, Provider provider) throws SQLException {int upRows = 0;PreparedStatement preparedStatement;// 检查数据库连接是否非空,确保可以安全地执行SQL语句if (connection != null) {// 准备更新供应商信息的SQL语句String sql = "update smbms_provider set " +"proCode=?, " +"proName=?, " +"proDesc=?, " +"proContact=?, " +"proPhone=?, " +"proAddress=?, " +"proFax=?, " +"modifyBy=?, " +"modifyDate=? " +"where id=?";// 初始化参数数组,用于存储供应商信息Object[] params = new Object[9];params[0] = provider.getProCode();params[1] = provider.getProName();params[2] = provider.getProDesc();params[3] = provider.getProContact();params[4] = provider.getProPhone();params[5] = provider.getProAddress();params[6] = provider.getProFax();params[7] = provider.getModifyBy();params[8] = provider.getModifyDate();// 准备SQL语句执行对象preparedStatement = connection.prepareStatement(sql);// 执行更新操作并获取影响的行数upRows = BaseDao.executeUpdate(connection, sql, preparedStatement, params);// 关闭资源,避免内存泄漏BaseDao.closeResource(connection, preparedStatement, null);}// 返回更新影响的行数return upRows;}
ProviderService
- ProviderService
int updateProvider(Provider provider) throws SQLException;
- ProviderServiceImpl
/*** 更新供应商信息* <p>* 此方法用于更新数据库中供应商的信息它接收一个Provider对象作为参数,* 该对象包含了需要更新的供应商的新信息方法通过调用providerDao的updateProvider* 方法来执行数据库更新操作如果更新过程中遇到异常,会进行回滚操作以确保数据一致性** @param provider 包含了需要更新的供应商信息的Provider对象* @return 返回更新影响的行数,用于判断更新操作是否成功* @throws SQLException 如果数据库操作失败,抛出此异常*/@Overridepublic int updateProvider(Provider provider) throws SQLException {int upRows = 0;Connection conn = null;try {// 获取数据库连接conn = BaseDao.connection();// 执行更新操作upRows = providerDao.updateProvider(conn, provider);} catch (SQLException e) {// 更新失败时,进行事务回滚conn.rollback();} finally {// 关闭数据库资源BaseDao.closeResource(conn, null, null);}return upRows;}
ProviderServlet
/*** 处理HTTP Post请求的方法* 根据请求参数中的method字段值,决定执行相应的操作** @param req HttpServletRequest对象,用于获取请求参数* @param resp HttpServletResponse对象,用于向客户端发送数据* @throws ServletException 如果Servlet操作失败* @throws IOException 如果发生输入输出异常*/@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// 获取请求参数中的method值,如果为空则默认为空字符串String method = req.getParameter("method") == null ? "" : req.getParameter("method");// 根据method值调用对应的方法执行操作switch (method) {case "modify":modifyProvider(req, resp);break;}}/*** 更新一条记录** @param req 用于获取请求信息和会话对象* @param resp 用于向客户端发送响应*/private void modifyProvider(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// 获取当前登录用户信息User user = (User) req.getSession().getAttribute(Constants.USER_SESSION);// 创建Provider对象,并从请求中获取参数来设置对象属性Provider provider = new Provider();provider.setId(Integer.parseInt(req.getParameter("id")));provider.setProName(req.getParameter("proName"));provider.setProCode(req.getParameter("proCode"));provider.setProDesc(req.getParameter("proDesc"));provider.setProContact(req.getParameter("proContact"));provider.setProPhone(req.getParameter("proPhone"));provider.setProAddress(req.getParameter("proAddress"));provider.setProFax(req.getParameter("proFax"));// 设置修改者为当前登录用户provider.setModifyBy(user.getId());// 设置修改时间为当前时间provider.setModifyDate(new Date());try {// 尝试更新数据库中的Provider记录if (providerService.updateProvider(provider) > 0) {// 如果更新成功,设置会话消息req.getSession().setAttribute("message", "数据更新成功!");} else {// 如果更新失败,设置会话消息req.getSession().setAttribute("message", "数据更新失败!");}} catch (SQLException e) {// 如果捕获到SQLException,则抛出运行时异常throw new RuntimeException(e);}// 跳转到列表页面req.getRequestDispatcher("/provider?method=view").forward(req, resp);}
查询供应商信息
需要两个方法
- getProviderCounts、
- getProviderList
ProviderDao
- ProviderDao
public List<Provider> getProviderList(Connection connection, String proName, String proCode) throws Exception;
- ProviderDaoImpl
/*** 根据供应商名称和编码获取供应商列表** @param connection 数据库连接对象,用于执行数据库操作* @param proName 供应商名称,用于筛选供应商列表* @param proCode 供应商编码,用于筛选供应商列表* @return 返回一个包含符合条件的供应商对象的列表* @throws Exception 如果数据库操作失败,抛出异常*/@Overridepublic List<Provider> getProviderList(Connection connection, String proName, String proCode) throws Exception {List<Provider> providers = new ArrayList<Provider>();Provider provider = new Provider();PreparedStatement preparedStatement;ResultSet resultSet = null;String sql = "select * from smbms_provider ";// 初始化参数列表,用于存储查询条件参数List<Object> list = new ArrayList<Object>();if (connection != null) {// 构建SQL查询语句sql += "where 1=1";// 如果供应商名称不为空,添加供应商名称模糊查询条件if (!proName.isEmpty()) {sql += "and proName like ? ";list.add("%" + proName + "%");}// 如果供应商编码不为空,添加供应商编码模糊查询条件if (!proCode.isEmpty()) {sql += "and proCode = ? ";list.add( proCode );}// 准备SQL语句执行对象preparedStatement = connection.prepareStatement(sql);// 执行查询并获取结果集resultSet = BaseDao.executeQuery(connection, sql, preparedStatement, list.toArray(),resultSet);// 遍历结果集,将每条记录转换为供应商对象,并添加到列表中while (resultSet.next()) {providers.add(getProviderByResult(resultSet));}// 关闭数据库资源BaseDao.closeResource(connection, preparedStatement, resultSet);}// 返回供应商列表return providers;}
ProviderService
- ProviderService
List<Provider> getProviderList(String proName, String proCode);
- ProviderServiceImpl
/*** 根据供应商名称和编码获取供应商列表** @param proName 供应商名称,用于模糊查询* @param proCode 供应商编码,用于精确查询* @return 返回一个包含查询结果的供应商列表如果查询结果为空,则返回一个空列表*/@Overridepublic List<Provider> getProviderList(String proName, String proCode) {// 初始化供应商列表List<Provider> providers = new ArrayList<>();// 获取数据库连接Connection conn = BaseDao.connection();try {// 调用Dao层方法,根据供应商名称和编码查询供应商列表providers = providerDao.getProviderList(conn, proName, proCode);} catch (Exception e) {// 异常处理:打印异常信息e.printStackTrace();} finally {// 关闭数据库连接BaseDao.closeConnection(conn);}// 返回查询到的供应商列表return providers;}
ProviderServlet
/*** 处理HTTP Post请求的方法* 根据请求参数中的method字段值,决定执行相应的操作** @param req HttpServletRequest对象,用于获取请求参数* @param resp HttpServletResponse对象,用于向客户端发送数据* @throws ServletException 如果Servlet操作失败* @throws IOException 如果发生输入输出异常*/@Overrideprotected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// 获取请求参数中的method值,如果为空则默认为空字符串String method = req.getParameter("method") == null ? "" : req.getParameter("method");// 根据method值调用对应的方法执行操作switch (method) {case "modify":modifyProvider(req, resp);break;}}/*** 获取多条记录** @param req 用于从HTTP请求中获取参数和设置属性* @param resp 用于发送HTTP响应*/private void getProviderList(HttpServletRequest req, HttpServletResponse resp) {// 从请求中获取查询参数String queryProCode = req.getParameter("queryProCode");String queryProName = req.getParameter("queryProName");// 对查询参数进行空值检查并赋予默认值queryProCode = queryProCode == null ? "" : queryProCode;queryProName = queryProName == null ? "" : queryProName;// 调用服务层方法获取供应商列表List<Provider> providerList = providerService.getProviderList(queryProCode, queryProName);try {if (providerList != null) {// 如果列表不为空,设置请求属性并转发到供应商列表页面req.setAttribute("providerList", providerList);req.getRequestDispatcher("/providerlist.jsp");} else {// 如果列表为空,重定向到供应商查询页面resp.sendRedirect(req.getContextPath() + "/provider?method=query");}} catch (Exception e) {// 异常处理: 打印异常信息e.printStackTrace();}}
订单管理
前期准备
- 创建供应商 、bill 的servlet
- 注册 bill 的servlet
- 创建相关的Dao,Service,javaBean等
- 导入相关的jsp
新增订单
billDao
- billDao
boolean addBill(Connection connection, Bill bill) throws SQLException;
- billDaoImpl
/*** @param connection 数据库连接对象* @param bill 订单对象* @return 添加结果*/@Overridepublic boolean addBill(Connection connection, Bill bill) throws SQLException {boolean addFlag = false;int addRows;PreparedStatement preparedStatement;String sql = "insert into smbms_bill values (null,?,?,?,?,?,?,?,?,?,?,?,?)";preparedStatement = connection.prepareStatement(sql);Object[] params = {bill.getBillCode(),bill.getProductName(),bill.getProductDesc(),bill.getProductUnit(),bill.getProductCount(),bill.getTotalPrice(),bill.getIsPayment(),bill.getCreatedBy(),bill.getCreationDate(),bill.getModifyBy(),bill.getModifyDate(),bill.getProviderId()};addRows = BaseDao.executeUpdate(connection, sql, preparedStatement, params);if (addRows > 0) {addFlag = true;}BaseDao.closeResource(connection, preparedStatement, null);return addFlag;}
s
billService
- billService
boolean addBill(Bill bill) throws SQLException;
- billServiceImpl
/*** 添加账单到数据库* <p>* 此方法负责将一个账单对象添加到数据库中它首先获取一个数据库连接,* 然后尝试使用账单DAO的addBill方法将账单添加到数据库中* 如果在添加过程中遇到SQLException,将抛出RuntimeException* 最后,无论添加是否成功,都会关闭数据库资源** @param bill 要添加到数据库的账单对象,包含账单的所有必要信息* @return boolean 表示账单是否成功添加到数据库中当前方法中此参数未被使用*/@Overridepublic boolean addBill(Bill bill) throws SQLException {Connection conn = null;boolean addFlag = false;try {// 获取数据库连接conn = BaseDao.connection();conn.setAutoCommit(false);// 调用账单DAO的添加方法,执行账单添加操作addFlag = billDao.addBill(conn, bill);conn.commit();} catch (Exception e) {e.printStackTrace();conn.rollback();} finally {// 关闭数据库资源,确保连接被释放回连接池BaseDao.closeResource(conn, null, null);}return addFlag;}
billServlet
- billServlet
/*** 获取账单列表* <p>* 此方法负责处理账单查询请求,根据不同的查询条件(如产品名称、供应商ID、是否已支付),* 从数据库中获取相应的账单信息,并进行分页处理,最后将结果展示在页面上** @param req 用于获取请求参数和设置请求属性* @param resp 用于实现请求转发或重定向* @throws ServletException 如果Servlet操作失败* @throws IOException 如果输入输出操作失败*/private void getBill(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// 默认值初始化String productName = "";int isPayment = 0;int providerId = 0;// 获取request参数String queryProductName = req.getParameter("queryProductName");String queryProviderId = req.getParameter("queryProviderId");String queryIsPayment = req.getParameter("queryIsPayment");String pageIndex = req.getParameter("pageIndex");// 默认分页设置int currentPageNo = 1;int pageSize = 5;// TODO: 处理查询条件,确保空值安全,isPayment、providerId --> intqueryProductName = queryProductName == null ? "" : queryProductName;queryProviderId = queryProviderId == null ? "" : queryProviderId;queryIsPayment = queryIsPayment == null ? "" : queryIsPayment;currentPageNo = pageIndex == null ? currentPageNo : Integer.parseInt(pageIndex);// 创建BillService实例BillService billService = new BillServiceImpl();// 获取账单总数int totalCount = billService.getBillCount(queryProductName, queryProviderId,queryIsPayment);// 创建PageSupport实例用于分页处理PageSupport pageSupport = new PageSupport();// 设置分页参数pageSupport.setTotalCount(totalCount);pageSupport.setPageIndex(currentPageNo);pageSupport.setPageSize(pageSize);// 计算总页数int totalPageCount = pageSupport.getTotalPageCount();// 校验当前页码if (currentPageNo < 1) {currentPageNo = 1;} else if (currentPageNo > totalPageCount) {currentPageNo = totalPageCount;}// 获取账单列表List<Bill> billList = billService.getBillList(queryProductName, queryProviderId,queryIsPayment);// 处理完的数据存到request中,用于页面展示req.setAttribute("billList", billList);req.setAttribute("queryProductName", queryProductName);req.setAttribute("queryProviderId", queryProviderId);req.setAttribute("queryIsPayment", queryIsPayment);req.setAttribute("totalPageCount", totalPageCount);req.setAttribute("totalCount", totalCount);req.setAttribute("currentPageNo", currentPageNo);// 跳转到list页面req.getRequestDispatcher("/billlist.jsp").forward(req, resp);}
- web.xml
<servlet><servlet-name>BillServlet</servlet-name><servlet-class>com.dashangms.servlet.bill.BillServlet</servlet-class></servlet><servlet-mapping><servlet-name>BillServlet</servlet-name><url-pattern>/jsp/bill.do</url-pattern></servlet-mapping><servlet-mapping><servlet-name>BillServlet</servlet-name><url-pattern>/bill</url-pattern></servlet-mapping>
jsp
<a href="${pageContext.request.contextPath}/jsp/billadd.jsp">添加订单</a>
取消订单
billDao
- billDao
int deleteBill(Connection connection, int delId) throws SQLException;
- billDaoImpl
/*** 根据给定的数据库连接和ID删除账单记录** @param connection 数据库连接对象,用于执行SQL语句* @param delId 要删除的账单的ID* @return 返回删除的行数,表示删除成功的记录数* @throws SQLException 如果执行SQL语句时发生错误*/
@Override
public int deleteBill(Connection connection, int delId) throws SQLException {// 初始化删除的行数为0int deletedRows = 0;// 初始化PreparedStatement对象为null,用于执行SQL语句PreparedStatement preparedStatement = null;// 检查数据库连接是否不为nullif (connection != null) {// 定义SQL语句,用于删除指定ID的账单记录String sql = "delete from smbms_bill where id=?";// 准备SQL语句preparedStatement = connection.prepareStatement(sql);// 创建一个包含要删除账单ID的参数数组Object[] param = {delId};// 执行更新操作并获取删除的行数deletedRows = BaseDao.executeUpdate(connection, sql, preparedStatement, param);}// 关闭数据库资源BaseDao.closeResource(connection, preparedStatement, null);// 返回删除的行数return deletedRows;
}
billService
- billService
boolean deleteBill(String delId) throws SQLException;
- billServiceImpl
/*** 根据ID删除账单** @param delId 要删除的账单的ID* @return 如果删除成功,返回true;否则返回false* @throws SQLException 如果与数据库交互时发生错误,抛出此异常*/@Overridepublic boolean deleteBill(String delId) throws SQLException {// 初始化删除标志为falseboolean deleteFlag = false;int delIdTmp = Integer.parseInt(delId != null ? delId : "0");// 定义数据库连接对象Connection conn = null;try {// 获取数据库连接conn = BaseDao.connection();// 设置手动管理事务conn.setAutoCommit(false);// 调用Dao层方法,执行删除操作int deleteRows = billDao.deleteBill(conn, delIdTmp);// 检查删除的行数,如果大于0,表示删除成功if (deleteRows > 0) {deleteFlag = true;}// 提交事务conn.commit();} catch (SQLException e) {// 打印异常信息e.printStackTrace();// 回滚事务conn.rollback();} finally {// 关闭数据库资源BaseDao.closeResource(conn, null, null);}// 返回删除标志return deleteFlag;}
billServlet
- billServlet
/*** 删除账单操作** 此方法用于处理从 HttpServletRequest 请求中获取的删除账单指令* 它调用 BillService 接口的实现来执行实际的删除操作,并根据删除结果* 设置 session 属性以提供反馈信息,然后重定向到账单查询页面** @param req 用于获取删除指令的 HTTP 请求对象* @param resp 用于重定向到查询页面的 HTTP 响应对象* @throws ServletException 如果 Servlet 操作失败* @throws IOException 如果输入/输出操作失败* @throws SQLException 如果与数据库的交互操作失败*/private void delBill(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException, SQLException {// 实例化 BillService 的实现类BillService billService = new BillServiceImpl();// 根据删除结果设置 session 属性和重定向消息if (billService.deleteBill(req.getParameter("delId"))) {req.getSession().setAttribute("message", "删除成功!");} else {req.getSession().setAttribute("message", "删除失败!");}// 重定向到账单查询页面resp.sendRedirect(req.getContextPath() + "/provider?method=query");// TODO: 前端使用ajax传递数据,需要转换为json格式}
- web.xml
jsp
<span><a class="deleteBill" href="javascript:;" billid=${bill.id} billcc=${bill.billCode}><img src="${pageContext.request.contextPath}/images/schu.png" alt="删除" title="删除"/></a></span>
更改订单信息
billDao
- billDao
int updateBill(Connection connection, Bill bill) throws SQLException;
- billDaoImpl
/*** 更新账单信息** @param connection 数据库连接对象,用于执行SQL语句* @param bill 账单对象,包含需要更新的账单信息* @return 返回受影响的行数,用于判断更新操作是否成功* @throws SQLException 如果执行SQL语句时发生错误,抛出此异常*/@Overridepublic int updateBill(Connection connection, Bill bill) throws SQLException {int updateRows = 0;PreparedStatement preparedStatement = null;// 定义更新账单信息的SQL语句String sql = "update smbms_bill set " +"billCode=?," +"productName=?, " +"productDesc=?," +"productUnit=?," +"productCount=?," +"totalPrice=?," +"isPayment=?," +"modifyBy=?," +"modifyDate=?," +"providerId=?" +"where id=?";// 准备SQL语句参数,按照顺序从bill对象中获取属性值Object[] params = {bill.getBillCode(),bill.getProductName(),bill.getProductDesc(),bill.getProductUnit(),bill.getProductCount(),bill.getTotalPrice(),bill.getIsPayment(),bill.getModifyBy(),bill.getModifyDate(),bill.getProviderId(),bill.getId()};// 执行更新操作并获取受影响的行数updateRows = BaseDao.executeUpdate(connection, sql, preparedStatement, params);// 关闭数据库连接BaseDao.closeConnection(connection);// 返回受影响的行数return updateRows;}
billService
- billService
boolean updateBill(Bill bill) throws SQLException;
- billServiceImpl
/*** 更新账单信息** @param bill 要更新的账单对象,包含账单的详细信息* @return 返回一个布尔值,表示账单信息是否更新成功* @throws SQLException 如果数据库操作失败,抛出SQLException*/@Overridepublic boolean updateBill(Bill bill) throws SQLException {// 初始化更新标志为false,用于表示账单信息是否更新成功boolean updateFlag = false;// 初始化更新行数为0,用于记录数据库中受影响的行数int updateRows = 0;// 声明数据库连接对象Connection conn = null;// 获取数据库连接updateBilltry {// 获取数据库连接conn = BaseDao.connection();// 设置连接为手动管理事务conn.setAutoCommit(false);// 调用BillDao的updateBill方法更新账单信息updateRows = billDao.updateBill(conn, bill);// 提交事务conn.commit();// 如果更新行数大于0,表示账单信息更新成功if (updateRows > 0) {updateFlag = true;}} catch (Exception e) {// 打印异常信息e.printStackTrace();// 回滚事务conn.rollback();} finally {// 关闭数据库资源BaseDao.closeResource(conn, null, null);}// 返回更新标志return updateFlag;}
billServlet
- billServlet
/*** 更新账单信息* * @param req 用于获取请求参数和会话信息* @param resp 用于重定向页面* @throws ServletException 如果Servlet操作失败* @throws IOException 如果输入/输出操作失败* @throws SQLException 如果数据库操作失败*/private void updateBill(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException, SQLException {// 实例化BillService接口和Bill类BillService billService = new BillServiceImpl();Bill bill = new Bill();// 从请求参数中设置账单属性bill.setBillCode(req.getParameter("billCode"));bill.setProductName(req.getParameter("productName"));bill.setProductDesc(req.getParameter("productDesc"));bill.setProductUnit(new BigDecimal(req.getParameter("productUnit")));bill.setProductCount(new BigDecimal(req.getParameter("productCount")));bill.setTotalPrice(req.getParameter("totalPrice"));bill.setIsPayment(Integer.parseInt(req.getParameter("isPayment")));bill.setProviderId(Integer.parseInt(req.getParameter("providerId")));bill.setId(Integer.parseInt(req.getParameter("id")));bill.setModifyBy(Integer.parseInt(req.getParameter("userId")));bill.setModifyDate(new Date());// 根据账单服务的更新结果决定重定向的页面和会话消息if (billService.updateBill(bill)) {req.getSession().setAttribute("message", "修改成功!");resp.sendRedirect(req.getContextPath() + "/provider?method=query");} else {req.getSession().setAttribute("message", "修改失败!");resp.sendRedirect(req.getContextPath() + "/provider?method=modify");}}
- web.xml
jsp
查询订单信息
billDao
- billDao
List<Bill> queryBillBy(Connection connection, String queryProductName, String queryProviderId, String queryIsPayment ) throws SQLException;
- billDaoImpl
/*** 查询订单详情* 根据请求过来的信息查询内容,返回结果,内容为空的时候显示所有订单** @param connection 数据库连接对象* @param queryProductName 商品名称* @param queryProviderId 商品id* @param queryIsPayment 是否付款* @return 订单列表*/@Overridepublic List<Bill> queryBillBy(Connection connection, String queryProductName,String queryProviderId, String queryIsPayment) throws SQLException {ResultSet resultSet = null;List<Bill> billList = new ArrayList<>();List<Object> params = new ArrayList<>();PreparedStatement preparedStatement;String sql = "select * from smbms_bill ";if (queryProductName != null || queryProviderId != null || queryIsPayment != null) {sql += "where 1=1 ";if (queryProductName != null && !queryProductName.isEmpty()) {sql += "and productName like ? ";params.add("%" + queryProductName + "%");}if (queryProviderId != null && !queryProviderId.isEmpty()) {sql += "and providerId = ? ";params.add(queryProviderId);}if (queryIsPayment != null && !queryIsPayment.isEmpty()) {sql += "and isPayment = ? ";params.add(queryIsPayment);}}preparedStatement = connection.prepareStatement(sql);resultSet = BaseDao.executeQuery(connection, sql, preparedStatement, params.toArray(),resultSet);while (resultSet.next()) {billList.add(getBillList(resultSet));}BaseDao.closeResource(connection, preparedStatement, resultSet);return billList;}
billService
- billService
/*** 获取所有订单列表** @param queryProductName 商品名称* @param queryProviderId 供应商* @param queryIsPayment 是否付款* @return 订单列表*/List<Bill> getBillList(String queryProductName,String queryProviderId, String queryIsPayment);
- billServiceImpl
/*** 获取所有订单列表** @param queryProductName 商品名称* @param queryProviderId 供应商* @param queryIsPayment 是否付款* @return 订单列表*/@Overridepublic List<Bill> getBillList(String queryProductName, String queryProviderId,String queryIsPayment) {List<Bill> billList;Connection con = BaseDao.connection();try {billList = billDao.queryBillBy(con, queryProductName, queryProviderId, queryIsPayment);} catch (SQLException e) {throw new RuntimeException(e);} finally {BaseDao.closeResource(con, null, null);}return billList;}
billServlet
- billServlet
/*** 获取账单列表* <p>* 此方法负责处理账单查询请求,根据不同的查询条件(如产品名称、供应商ID、是否已支付),* 从数据库中获取相应的账单信息,并进行分页处理,最后将结果展示在页面上** @param req 用于获取请求参数和设置请求属性* @param resp 用于实现请求转发或重定向* @throws ServletException 如果Servlet操作失败* @throws IOException 如果输入输出操作失败*/private void getBill(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {// 默认值初始化String productName = "";int isPayment = 0;int providerId = 0;// 获取request参数String queryProductName = req.getParameter("queryProductName");String queryProviderId = req.getParameter("queryProviderId");String queryIsPayment = req.getParameter("queryIsPayment");String pageIndex = req.getParameter("pageIndex");// 默认分页设置int currentPageNo = 1;int pageSize = 5;// TODO: 处理查询条件,确保空值安全,isPayment、providerId --> intqueryProductName = queryProductName == null ? "" : queryProductName;queryProviderId = queryProviderId == null ? "" : queryProviderId;queryIsPayment = queryIsPayment == null ? "" : queryIsPayment;currentPageNo = pageIndex == null ? currentPageNo : Integer.parseInt(pageIndex);// 创建BillService实例BillService billService = new BillServiceImpl();// 获取账单总数int totalCount = billService.getBillCount(queryProductName, queryProviderId,queryIsPayment);// 创建PageSupport实例用于分页处理PageSupport pageSupport = new PageSupport();// 设置分页参数pageSupport.setTotalCount(totalCount);pageSupport.setPageIndex(currentPageNo);pageSupport.setPageSize(pageSize);// 计算总页数int totalPageCount = pageSupport.getTotalPageCount();// 校验当前页码if (currentPageNo < 1) {currentPageNo = 1;} else if (currentPageNo > totalPageCount) {currentPageNo = totalPageCount;}// 获取账单列表List<Bill> billList = billService.getBillList(queryProductName, queryProviderId,queryIsPayment);// 处理完的数据存到request中,用于页面展示req.setAttribute("billList", billList);req.setAttribute("queryProductName", queryProductName);req.setAttribute("queryProviderId", queryProviderId);req.setAttribute("queryIsPayment", queryIsPayment);req.setAttribute("totalPageCount", totalPageCount);req.setAttribute("totalCount", totalCount);req.setAttribute("currentPageNo", currentPageNo);// 跳转到list页面req.getRequestDispatcher("/billlist.jsp").forward(req, resp);}
- web.xml
jsp
优化补充
疏通页面,修改Bug
功能点:
- 用户管理
- 供应商管理
- 订单管理
- 分页功能
分页功能异常
添加分页功能后显示
错误代码:
解释:在进行模除运算是分母为0;
解决思路及方案:
1. 检查内容赋值,debug断点查看崩溃点,发现是 `this.totalPageCount = totalCount % pageSize == 0 ? totalCount / pageSize :totalCount / pageSize + 1;` 这部分的`pageSize=0`,检查什么时候进行赋值,赋值是否出现异常;
2. 经检查发现, `setTotalCount()` 被先调用,而 `pageSize` 还是初始值 0,所以出现报错。为避免该情况错误出现,在`setTotalCount()`方法中进行防御性默认值追加判断;为解决这次出现的问题,检查是否赋值正常,是否先赋值后调用的该方法。
没有查出数据的时候分页显示错误
错误:
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ‘-5, 5’ at line 1
解决思路和方案:
在SQL查询到时候设定范围选择了负数导致出现了**负数偏移量**,使用LIMIT
的时候第一个offset不能为负数;
java.sql.SQLException: Before start of result set
错误:
java.sql.SQLException: Before start of result set
是由于在尝试从 ResultSet
获取数据之前,没有调用 resultSet.next() 来将光标移动到结果集的第一行。ResultSet 初始时的光标位于第一行之前,如果不调用 next(),直接调用 getInt()、getString() 等方法就会抛出该异常。
解决思路和方案:
在获取 resultSet 后调用 resultSet.next(),确保光标移动到了有效行。
if (resultSet != null && resultSet.next()) xxx;
页面显示的时候分页功能不能用
错误:
分页功能操作的时候不能翻页
解决方案和思路:
- 检查SQL语句是否加上了
Limit
关键字,分页显示的数据需要是SQL查询的; ps:需要进行DB交互; - 添加完正常分页显示,但是分页功能不能使用,检查前端代码是否正常发送请求;
- 在
form
表单中添加pageIndex
的hidden项,如果没有pageIndex
参数,request.getParameter("pageIndex")
就会是null
,就会报错或者默认取第一页;如果参数没有,则会出现:- 默认只返回第一页数据;
- 或者抛出异常、找不到参数;
- 或者压根不知道用户想翻页;
section标签
<section>
标签在 HTML 中用于定义文档中的一个独立的、结构化的部分,通常与文档的主题、内容区分相关。它主要用于将内容分割成不同的部分,帮助提升页面的可读性和可维护性
用于提高网页的可访问性和 SEO 优化。
<section>
并不应该用于普通的容器(如果只是用来包裹样式或布局内容,应该使用<div>
)。它应该包含具有特定意义的内容块。- 使用
<section>
时,最好每个部分都有一个标题(<h1>、<h2>
等),以确保文档的语义结构清晰。
java.sql.SQLSyntaxErrorException
该问题由于 SQL 语句中使用了错误的关键字 by 而非 ORDER BY 所致。通过修正 SQL 语法即可解决。同时建议对 SQL 拼接逻辑进行规范化处理,提升代码可维护性和健壮性。
但是检查代码之后发现使用的关键字确为order by
,怀疑是因为字段拼接时没有使用空格;
修改完成后,问题解决;
获取下拉框内容失败
检查代码逻辑发现读取不到下拉框列表内容,Servlet添加读取获取下拉列表信息的逻辑,debug检查后发现是
不使用ajax
- Servlet 中查询角色列表并转发给 JSP
// UserServlet.java
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {List<Role> roleList = roleService.getAllRoles(); // 从数据库获取角色列表request.setAttribute("roleList", roleList); // 设置到 request 域中request.getRequestDispatcher("/jsp/useradd.jsp").forward(request, response);
}
- 在 JSP 页面中直接渲染下拉框
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%><select name="userRole" id="userRole"><option value="0">请选择</option><c:forEach items="${roleList}" var="role"><option value="${role.id}">${role.roleName}</option></c:forEach>
</select>
详细在实际项目 https://gitee.com/RS0582/javaSWebServlet 中
使用ajax,需要使用alibaba的fastjson.JSONArray
- 依赖导入
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson --><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>2.0.42</version></dependency>
- 绑定jsp的标签
<select name="userRole" id="userRole"> </select>
- 在js中使用ajax传递,获取请求的URL调用改Servlet的方法,请求成功 按照指定的格式显示
let userRole;$(function(){userRole = $("#userRole");//渲染角色下拉列表$.ajax({type:"GET",//请求类型url:path+"/user",//请求的urldata:{method:"getRoleList"},//请求参数dataType:"json",//ajax接口(请求url)返回的数据类型success:function(data){//data:返回数据(json对象)if(data != null){ //如果数据不为空,则html添加optionsuserRole.html("");let options = "<option value=\"0\">请选择</option>";for(let i = 0; i < data.length; i++){options += "<option value=\"" + data[i].id + "\">" + data[i].roleName + "</option>";}userRole.html(options);}},error:function(data){//当访问时候,404,500 等非200的错误状态码validateTip(userRole.next(),{"color":"red"},imgNo+" 获取用户角色列表error",false);}});// 绑定userRoleuserRole.bind("focus",function(){validateTip(userRole.next(),{"color":"#666666"},"* 请选择用户角色",false);}).bind("blur",function(){if(userRole.val() != null && userRole.val() > 0){validateTip(userRole.next(),{"color":"green"},imgYes,true);}else{validateTip(userRole.next(),{"color":"red"},imgNo + " 请重新选择用户角色",false);}});
}
- 在Servlet中写调用方法
getRoleList
获取Role列表
resp.setContentType("application/json");PrintWriter writer = resp.getWriter();writer.write(JSONArray.toJSONString(roleList)); // 写入jsonwriter.close();
private void getRoleList(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {List<Role> roleList = roleService.getRoleList();resp.setContentType("application/json");PrintWriter writer = resp.getWriter();writer.write(JSONArray.toJSONString(roleList));writer.close();}public List<Role> getRoleList() {List<Role> roleList = null;Connection connection = DBUtil.getConnection();try {roleList = roleDao.getRoleList(connection);} catch (Exception e) {e.printStackTrace();} finally {DBUtil.closeConnection(connection);}return roleList;}public List<Role> getRoleList(Connection connection) throws Exception{List<Role> roleList = new ArrayList<>();if (connection != null) {PreparedStatement preparedStatement = null;ResultSet rs = null;String sql = "select * from smbms_role";rs = DBUtil.query(connection, preparedStatement, rs, sql ,null);while (rs.next()) {roleList.add(getRoleByResult(rs));}DBUtil.closeResource(preparedStatement, rs);}return roleList;}
优化逻辑,根据代码检测工具(SonarQube)优化代码
追加log4j
疏通错误看log,以及抛出异常的时候总是显示异常处理 使用throw new Exception()
不好,对应点增加log4j,使用log4j管理。
- 依赖导入
<!-- Log4j2 Core -->
<dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-core</artifactId><version>2.17.1</version>
</dependency><!-- Log4j2 API -->
<dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-api</artifactId><version>2.17.1</version>
</dependency><!-- 如果你在 Web 项目中使用 Servlet,还需要这个 -->
<dependency><groupId>org.apache.logging.log4j</groupId><artifactId>log4j-web</artifactId><version>2.17.1</version>
</dependency>
- 声明对象,导入包
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;private static final Logger logger = LogManager.getLogger(UserServlet.class);if (logger.isDebugEnabled()) {logger.debug("method:" + method );
}
- 配置log4j2.xml
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="WARN"><Appenders><!-- 控制台输出 --><Console name="Console" target="SYSTEM_OUT"><!-- 控制台显示,显示时间 代码所在行数 log内容 --><PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} [%t] %-5level %logger{36} - %msg%n"/></Console><!-- 文件输出 --><File name="File" fileName="target/app.log"><PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} %-5level %logger{36} - %msg%n"/></File></Appenders><Loggers><!-- 根 Logger 配置 --><Root level="info"><AppenderRef ref="Console"/><AppenderRef ref="File"/></Root><!-- Custom Logger for a specific package --><Logger name="com.dashangms" level="debug" additivity="false"><AppenderRef ref="Console"/><AppenderRef ref="File"/></Logger></Loggers>
</Configuration>
个别部分优化点
优化点1:所有的SQL拼接语句全部使用StringBuilder 处理,减少内存雍余;
- 原因:
- String 是不可变对象,每次拼接都会创建新对象,效率低。
- 特别是在循环或条件判断中频繁拼接时,性能下降明显。
优化点2:所有的字段都统一使用Constants管理
- 原因:
- 提高代码的一致性
- 减少错误
- 真正固定不变且很少被引用的值,可能没有必要创建常量
优化点3:
打印异常处理的逻辑使用log4j
- 原因:
- 对 ‘printStackTrace()’ 的调用可能应当替换为更可靠的日志
- 检查信息: 报告对无实参的 Throwable.printStackTrace() 的调用。
- 此类语句通常用于临时调试,应当从生产代码中移除,或者替换为更稳健的日志记录工具
优化点4:使用同一构造函数,避免多次重复调用
- 原因:
- 减少代码重复
- 提高代码的可维护性
统一管理,易于更新和修改 - 优化性能:减少对象实例化次数,提高代码的执行效率,减少不必要的资源浪费。
- 提高代码的可读性:减少复杂度
- 遵循面向对象编程原则
避免不必要的重载:在面向对象编程中,使用构造函数的重载(即多个构造函数)时,应该遵循"一个构造函数处理一个逻辑"的原则。避免过多的构造函数重载可以提升代码的稳定性。
优化点5:页面调整
- 页面foot部分颜色 :使用snipaste等工具确定主色块
- 图标同色系嵌合:使用阿里巴巴图标库
- 验证码
- 页面跳转有两种方法进行,格局实际情况调整页面跳转逻辑
- ①页面转发:
request.getRequestDispatcher("/jsp/index.jsp").forward(request,response)
; - ②重定向:
response.sendRedirect("/jsp/index.jsp")
;
- ①页面转发:
场景 | 方法 |
---|---|
提交表单后跳转列表页 | sendRedirect |
查询后展示结果页面 | forward |
保持地址栏不变继续处理 | forward |
防止用户刷新重复提交 | sendRedirect |
从 Servlet 跳转到 JSP 页面 | forward |