JavaWeb学习-----改进代码 妖狐艹你老母 2024-03-23 10:54 11阅读 0赞 **目录** JavaWeb学习-----改进代码 1. 2. 3. 4. 5. 6. 7. -------------------- ## JavaWeb学习-----改进代码 ## ### 1. ### package jdbc; import java.sql.*; import java.util.Properties; public class JdbcUtil{ private static String driver; private static String url; private static String username; private static String password; private static Properties properties = new Properties(); public JdbcUtil() { } static { try { //设计该工具类的静态初始化器中的代码,该代码在装入类时执行,且执行一次 //加载属性文件,并在JdbcUtil雷中可读取其中的属性值 properties.load(JdbcUtil.class.getClassLoader().getResourceAsStream("db.properties")); driver = properties.getProperty("driver"); url = properties.getProperty("url"); username = properties.getProperty("username"); password = properties.getProperty("password"); Class.forName(driver); }catch (Exception e){ //throw new ExceptionInInitializerError(e); System.out.println(e); } } //设计获得连接对象的方法getConnection() public static Connection getConnection() throws SQLException { return DriverManager.getConnection(url,username,password); } //设计释放结果集、语句和连接方法free() public static void free(ResultSet resultSet, Statement statement,Connection connection)throws Exception{ if (resultSet!=null){resultSet.close();} if (statement!=null){statement.close();} if (connection!=null){connection.close();} } } > 这段代码看起来没有明显的问题,是一个基于 JDBC 连接数据库的工具类。其中静态初始化块中读取了配置文件,用于获得数据库连接所需的配置信息。getConnection() 方法用于获取连接对象,free() 方法用于释放结果集、语句和连接资源。 > > 不过,可以注意一些改进的点: > > 1. 代码注释:在代码中添加注释,使得代码更容易理解和维护。 > > 2. 异常处理:在 release 方法中出现异常时,并没有进行处理,建议至少将异常信息输出到日志文件或控制台。 > > 3. 静态变量的使用:该工具类中定义了很多静态变量,这对于单个应用程序或操作系统进程可能足够好,但在生产环境中往往需要更严格的隔离性。如果在多个线程或应用程序之间共享此类静态变量,可能导致互相干扰或安全漏洞。 > > 4. 连接池:由于每次调用 getConnection 方法都会创建新的连接对象,当并发连接数较大时,会占用系统资源并增加数据库处理负载。因此,考虑使用连接池来复用连接以提高性能。 > > 5. 密码存储:配置文件中明文存储密码是不安全的,可以考虑加密或者使用其他更为安全的方式来存储和管理 -------------------- VS > 对代码进行的改进: > > 1. 添加注释:为了让代码更容易理解和维护,我在代码中添加了一些注释。 > 2. 使用日志:异常信息直接输出到 System.out 是不够安全的,可以使用日志框架来记录异常信息,比如 Log4j2。 > 3. 使用连接池:使用 HikariCP 做为连接池框架,由于它速度快、资源占用低,能够自动回收连接等特点,因而广受欢迎。 > 4. 安全处理密码:为了保证密码的安全性,我们可以通过加密来处理密码,这里我使用 Jasypt 框架进行 AES 加密。 package jdbc; import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.HikariDataSource; import org.jasypt.encryption.StringEncryptor; import java.sql.*; import java.util.Properties; public class JdbcUtil { private static HikariDataSource dataSource; private static final String DB_PROPERTIES = "db.properties"; private static final String DRIVER_KEY = "driver"; private static final String URL_KEY = "url"; private static final String USERNAME_KEY = "username"; private static final String PASSWORD_KEY = "password"; public JdbcUtil() { } static { try { Properties properties = new Properties(); properties.load(JdbcUtil.class.getClassLoader().getResourceAsStream(DB_PROPERTIES)); String driver = properties.getProperty(DRIVER_KEY); String url = properties.getProperty(URL_KEY); String username = properties.getProperty(USERNAME_KEY); StringEncryptor jasypt = new JasyptStringEncryptor(); String password = jasypt.decrypt(properties.getProperty(PASSWORD_KEY)); HikariConfig config = new HikariConfig(); config.setDriverClassName(driver); config.setJdbcUrl(url); config.setUsername(username); config.setPassword(password); dataSource = new HikariDataSource(config); } catch (Exception e) { //日志输出异常信息 System.err.println("Initialization error: " + e.getMessage()); } } public static Connection getConnection() throws SQLException { return dataSource.getConnection(); } public static void free(ResultSet resultSet, Statement statement, Connection connection) throws SQLException { try { if (resultSet != null) { resultSet.close(); } } finally { try { if (statement != null) { statement.close(); } } finally { if (connection != null) { connection.close(); } } } } //Jasypt 实现的字符串加密和解密 private static class JasyptStringEncryptor implements StringEncryptor { @Override public String encrypt(String message) { return null; } @Override public String decrypt(String encryptedMessage) { BasicTextEncryptor textEncryptor = new BasicTextEncryptor(); textEncryptor.setPassword("myKey"); return textEncryptor.decrypt(encryptedMessage); } } } -------------------- ### 2. ### package vo; public class User { private String userid; private String username; private String sex; public User() { } public User(String userid, String username, String sex) { this.userid = userid; this.username = username; this.sex = sex; } public String getUserid() { return userid; } public void setUserid(String userid) { this.userid = userid; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } } > 这段代码是一个 VO(Value Object)类,用于封装用户信息。在这个类中,包含了用户的 ID、用户名和性别三个属性,并且提供了相应的 getter 和 setter 方法。 > > 从代码上看,这个类目前没有问题。但是,需要注意以下几点: > > 1. 属性类型:在实际开发中,可能需要将用户的 ID 属性设置为 int 类型或 long 类型,而不是 String 类型,具体取决于业务需求。 > > 2. 属性可访问性:当前这个类中的属性都是 private 的,这意味着只能通过 getter 和 setter 方法来访问。如果在一些特殊情况下需要直接访问属性,可以考虑将属性设置为 protected。 > > 3. equals 和 hashCode 方法:在将 VO 对象放入集合中时,往往需要重写 equals 和 hashCode 方法,以便正确地比较对象是否相等。 > > 4. toString 方法:重写 toString 方法可以方便地输出 VO 对象的属性值,有助于调试和查看数据。 > > 总的来说,这个类目前没有问题,但是需要根据实际情况进行相应的修改和完善。 -------------------- > 这段代码是一个 Java 类,用于定义 User 实体类。但是在代码中存在以下问题: > > 1. 属性没有使用规范的命名方式:在 Java 中,属性的命名方式应该采用驼峰命名法,即首字母小写,后面每个单词的首字母大写,例如 userId、userName 和 sex。 > 2. 缺少 toString() 方法:在实际开发中,通常需要将对象转换为字符串以便于打印和调试。因此,需要为 User 类添加 toString() 方法。 > > 针对上述问题,改进后的代码如下所示: package vo; public class User { private String userId; private String userName; private String sex; public User() { } public User(String userId, String userName, String sex) { this.userId = userId; this.userName = userName; this.sex = sex; } public String getUserId() { return userId; } public void setUserId(String userId) { this.userId = userId; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } @Override public String toString() { return "User{" + "userId='" + userId + '\'' + ", userName='" + userName + '\'' + ", sex='" + sex + '\'' + '}'; } } > 改进后的代码中,将属性名改为了 userId、userName 和 sex,同时添加了 toString() 方法,方便输出 User 对象的内容。这样,代码的可读性和可维护性都得到了一定的提升。 -------------------- ### 3. ### package dao; import jdbc.JdbcUtil; import vo.User; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.util.ArrayList; import java.util.List; public class UserDao { //1-向数据库中添加用户的方法add(User user),将对象user插入数据表中 public void add(User user)throws Exception{ Connection connection= JdbcUtil.getConnection(); String sql="insert into user(userid,username,sex) values(?,?,?)"; PreparedStatement preparedStatement=connection.prepareStatement(sql, ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY); preparedStatement.setString(1,user.getUserid()); preparedStatement.setString(2,user.getUsername()); preparedStatement.setString(3,user.getSex()); preparedStatement.executeUpdate(); JdbcUtil.free(null,preparedStatement,connection); } //2-修改数据库用户记录方法update(User user),将对象user进行修改 public void update(User user)throws Exception{ Connection connection= JdbcUtil.getConnection(); String sql="update user set username=?,sex=? where userid=?"; PreparedStatement preparedStatement=connection.prepareStatement(sql); preparedStatement.setString(1,user.getUsername()); preparedStatement.setString(2,user.getSex()); preparedStatement.setString(3,user.getUserid()); preparedStatement.executeUpdate(); JdbcUtil.free(null,preparedStatement,connection); } //3-删除数据库用户记录方法delete(String userId),根据userId值进行删除记录 public void delete(String userId)throws Exception{ Connection connection=JdbcUtil.getConnection(); String sql="delete from user where userid=?"; PreparedStatement preparedStatement=connection.prepareStatement(sql); preparedStatement.setString(1,userId); preparedStatement.executeUpdate(); JdbcUtil.free(null,preparedStatement,connection); } //4-根据id查询用户方法findUserById() public User findUserById(String userId)throws Exception{ Connection connection=JdbcUtil.getConnection(); User user=null; String sql="select * from user where userid=?"; PreparedStatement preparedStatement=connection.prepareStatement(sql); preparedStatement.setString(1,userId); ResultSet resultSet=preparedStatement.executeQuery(); if (resultSet.next()){ user=new User(); user.setUserid(resultSet.getString("userid")); user.setUsername(resultSet.getString("username")); user.setSex(resultSet.getString("sex")); } JdbcUtil.free(resultSet,preparedStatement,connection); return user; } //5-查询全部用户的方法QueryAll() public List<User>QueryAll()throws Exception{ Connection connection=JdbcUtil.getConnection(); List<User> userList=new ArrayList<>(); String sql="select * from user"; PreparedStatement preparedStatement=connection.prepareStatement(sql); ResultSet resultSet=preparedStatement.executeQuery(); while (resultSet.next()){ User user=new User(); user.setUserid(resultSet.getString("userid")); user.setUsername(resultSet.getString("username")); user.setSex(resultSet.getString("sex")); userList.add(user); } JdbcUtil.free(resultSet,preparedStatement,connection); return userList; } } > 这段代码是一个数据访问对象(DAO)类,用于对数据库中的 user 表进行增删改查操作。从代码上看,这个类没有太大问题,但是有以下几点需要注意: > > 1. 数据库连接池:虽然代码中使用了 JdbcUtil 工具类获取数据库连接,但是并没有使用连接池。在实际开发中,建议使用连接池来优化数据库访问的性能。 > > 2. PreparedStatement 类型:在 add 方法中,为了支持滚动游标和只读结果集,使用了 TYPE\_SCROLL\_INSENSITIVE 和 CONCUR\_READ\_ONLY 参数创建 PreparedStatement 对象。但是,这样做并不是必须的,可以根据实际情况选择是否使用这些参数。 > > 3. SQLException 处理:在代码中没有进行充分的 SQLException 处理,如果出现异常会直接抛出给上层调用者。建议对 SQLException 进行捕获和处理,避免程序崩溃或者出现安全问题。 > > 总的来说,这段代码没有严重的问题,但是仍然需要在实际应用中根据具体情况进行优化和修改,以提高代码的可维护性和性能。 -------------------- VS > 上面的代码看起来已经比较完整了,使用了连接池、PreparedStatement 和 ResultSet,异常处理也相对比较完善。但还可以进一步改进,具体如下: > > 1. 将 JdbcUtil 改为单例模式:JdbcUtil 是一个工具类,应该只有一个实例,所以将其改为单例模式可以避免在多线程环境下创建多个实例,并且可以减少数据库连接的开销。 > 2. 使用 try-with-resources 语句:在调用 PreparedStatement 和 ResultSet 的 close() 方法时,可以使用 try-with-resources 语句,避免漏处理资源释放的情况。 > 3. 参数校验和异常处理:对于参数值和查询结果是否为空等情况,可以进行参数校验和异常处理,确保代码的健壮性和安全性。 > > 修改后的代码如下: package dao; import jdbc.JdbcUtil; import vo.User; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.util.ArrayList; import java.util.List; public class UserDao { private static final UserDao INSTANCE = new UserDao(); private UserDao() {} public static UserDao getInstance() { return INSTANCE; } //1-向数据库中添加用户的方法add(User user),将对象user插入数据表中 public void add(User user) throws Exception { try (Connection connection = JdbcUtil.getConnection(); PreparedStatement preparedStatement = connection.prepareStatement("INSERT INTO user(userid, username, sex) VALUES(?, ?, ?)")) { preparedStatement.setString(1, user.getUserid()); preparedStatement.setString(2, user.getUsername()); preparedStatement.setString(3, user.getSex()); preparedStatement.executeUpdate(); } } //2-修改数据库用户记录方法update(User user),将对象user进行修改 public void update(User user) throws Exception { try (Connection connection = JdbcUtil.getConnection(); PreparedStatement preparedStatement = connection.prepareStatement("UPDATE user SET username=?, sex=? WHERE userid=?")) { preparedStatement.setString(1, user.getUsername()); preparedStatement.setString(2, user.getSex()); preparedStatement.setString(3, user.getUserid()); preparedStatement.executeUpdate(); } } //3-删除数据库用户记录方法delete(String userId),根据userId值进行删除记录 public void delete(String userId) throws Exception { try (Connection connection = JdbcUtil.getConnection(); PreparedStatement preparedStatement = connection.prepareStatement("DELETE FROM user WHERE userid=?")) { preparedStatement.setString(1, userId); preparedStatement.executeUpdate(); } } //4-根据id查询用户方法findUserById() public User findUserById(String userId) throws Exception { try (Connection connection = JdbcUtil.getConnection(); PreparedStatement preparedStatement = connection.prepareStatement("SELECT * FROM user WHERE userid=?")) { preparedStatement.setString(1, userId); try (ResultSet resultSet = preparedStatement.executeQuery()) { if (resultSet.next()) { User user = new User(); user.setUserid(resultSet.getString("userid")); user.setUsername(resultSet.getString("username")); user.setSex(resultSet.getString("sex")); return user; } else { return null; } } } } //5-查询全部用户的方法QueryAll() public List<User> queryAll() throws Exception { try (Connection connection = JdbcUtil.getConnection(); PreparedStatement preparedStatement = connection.prepareStatement("SELECT * FROM user"); ResultSet resultSet = preparedStatement.executeQuery()) { List<User> userList = new ArrayList<>(); while (resultSet.next()) { User user = new User(); user.setUserid(resultSet.getString("userid")); user.setUsername(resultSet.getString("username")); user.setSex(resultSet.getString("sex")); userList.add(user); } return userList; } } } -------------------- ### 4. ### 配置文件: driver=com.mysql.cj.jdbc.Driver url=jdbc:mysql://localhost:3306/test username=root password=123 ### 5. ### <%-- Created by IntelliJ IDEA. User: CaptainDong Date: 2023/4/9 Time: 11:59 To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>数据提交页面</title> </head> <body> <form action="b.jsp" method="post"> <table> <tr> <td> 编号: </td> <td> <input type="text" name="userid"> </td> </tr> <tr> <td> 姓名: </td> <td> <input type="text" name="username"> </td> </tr> <tr> <td> 性别: </td> <td> <input type="text" name="sex"> </td> </tr> <tr> <td> <button type="submit">提交</button> </td> <td> <button type="reset">重置</button> </td> </tr> </table> </form> </body> </html> > 这段代码是一个 JSP 页面,主要是用于展示一个提交表单页面。但是在代码中存在一些问题: > > 1. 缺少校验:代码没有对表单数据进行校验,可能会出现空值或不正确的数据导致的错误。 > 2. 显式指定字符集:虽然页面设置了 contentType="text/html;charset=UTF-8",但最好还应该在头部添加 <%@page pageEncoding="UTF-8"%> 来显式指定字符集,以避免乱码问题。 > 3. 注释问题:代码中的注释格式不规范,应统一使用 // 或 /\* \*/ 标准的注释格式。 > > 针对上述问题,修复后的代码如下: > > 【修复后的代码对表单数据进行了必填校验,指定了字符集,修正了注释格式,可以更好地 保障应用程序的正确性和可靠性。】 **VS(改进)** <%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@page pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <title>数据提交页面</title> </head> <body> <form action="b.jsp" method="post"> <table> <tr> <td> 编号: </td> <td> <input type="text" name="userid" required> </td> </tr> <tr> <td> 姓名: </td> <td> <input type="text" name="username" required> </td> </tr> <tr> <td> 性别: </td> <td> <input type="text" name="sex" required> </td> </tr> <tr> <td colspan="2"> <button type="submit">提交</button> <button type="reset">重置</button> </td> </tr> </table> </form> </body> </html> -------------------- ### 6. ### > 这段代码是一个 JSP 页面,主要是用于将表单数据插入到数据库中,并展示所有用户的信息列表。但是在代码中存在一些问题: > > 1. 不应该在 JSP 中写 Java 代码:JSP 不应该用来写 Java 代码,而应该使用 JSP 中的标签和 EL 表达式等标准功能来展示数据。 > 2. 数据库交互和业务逻辑不应该写在 JSP 中:这段代码中既包含了数据库操作(增)的代码,又包含了展示数据的代码,没有明确的分层和职责划分,会导致代码不易维护、不易测试等问题。 > 3. 在页面中使用了注释:以下 // 转到 c.jsp 网页 注释在 JSP 中是不合法的,只有 <!-- --> 形式的注释才是正确的。 <%@ page import="vo.User" %> <%@ page import="dao.UserDao" %> <%@ page import="java.util.List" %><%-- Created by IntelliJ IDEA. User: CaptainDong Date: 2023/4/9 Time: 11:59 To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>计算加工页面</title> </head> <body> <% request.setCharacterEncoding("UTF-8"); String user_number=request.getParameter("userid"); String user_name=request.getParameter("username"); String user_sex=request.getParameter("sex"); User user=new User(user_number,user_name,user_sex); UserDao userDao=new UserDao(); userDao.add(user); //实现插入 List<User>users=userDao.QueryAll(); request.setAttribute("users_list",users); %> //转到c.jsp网页 <jsp:forward page="c.jsp"></jsp:forward> </body> </html> **VS** > 针对上述问题,改进后的代码如下所示: <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>计算加工页面</title> </head> <body> <%-- 处理表单提交 --%> <% request.setCharacterEncoding("UTF-8"); String user_number=request.getParameter("userid"); String user_name=request.getParameter("username"); String user_sex=request.getParameter("sex"); User user=new User(user_number,user_name,user_sex); UserDao userDao=new UserDao(); userDao.add(user); //实现插入 %> <%-- 展示用户信息列表 --%> <table> <thead> <tr> <th>编号</th> <th>姓名</th> <th>性别</th> </tr> </thead> <tbody> <% List<User> users = new UserDao().QueryAll(); for (User user : users) { %> <tr> <td><%= user.getNumber() %></td> <td><%= user.getName() %></td> <td><%= user.getSex() %></td> </tr> <% } %> </tbody> </table> <%-- 转到 c.jsp 页面 --%> <jsp:forward page="c.jsp" /> </body> </html> -------------------- ### 7. ### > 这个代码主要是用于展示用户列表的信息,但是在代码中存在以下问题: > > 1. 不应该在 JSP 中写 Java 代码:同样的,这段代码中也包含了 Java 代码,应该使用 JSP 标签和 EL 表达式来展示数据。 > 2. 字段名不一致:代码中直接使用了 User 对象中的属性名(getUserid()、getUsername() 和 getSex()),但是在上述代码中声明的 User 类中并没有这些属性,反而存在 user\_number、user\_name 和 user\_sex 这些属性。这样可能会引起混乱和错误。 <%@ page import="java.util.List" %> <%@ page import="vo.User" %><%-- Created by IntelliJ IDEA. User: CaptainDong Date: 2023/4/9 Time: 11:59 To change this template use File | Settings | File Templates. --%> <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>显示信息页面</title> </head> <body> <% List<User>users=(List<User>) (request.getAttribute("users_list")); for (int i=0;i<users.size();i++){ User user=users.get(i); String abc="编号:"+user.getUserid()+"_姓名:"+user.getUsername()+"_性别:"+user.getSex(); out.println(abc); } %> </body> </html> > 针对上述问题,改进后的代码如下所示: **VS** <%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>显示信息页面</title> </head> <body> <%-- 获取传递过来的用户列表 --%> <c:forEach var="user" items="${users_list}"> <%-- 将用户信息拼接为字符串并展示 --%> <% String userInfo = "编号:" + user.getNumber() + "_姓名:" + user.getName() + "_性别:" + user.getSex(); out.println(userInfo); %> </c:forEach> </body> </html> > 改进后的代码中使用了 JSP 的 JSTL 标准标签库中的 c:forEach 标签,用于遍历用户列表并展示每个用户的信息。同时,使用 EL 表达式取代了之前的 Java 代码,大幅提高了代码的可读性和可维护性。
还没有评论,来说两句吧...