目录
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
对代码进行的改进:
添加注释:为了让代码更容易理解和维护,我在代码中添加了一些注释。
使用日志:异常信息直接输出到 System.out 是不够安全的,可以使用日志框架来记录异常信息,比如 Log4j2。
使用连接池:使用 HikariCP 做为连接池框架,由于它速度快、资源占用低,能够自动回收连接等特点,因而广受欢迎。
安全处理密码:为了保证密码的安全性,我们可以通过加密来处理密码,这里我使用 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 实体类。但是在代码中存在以下问题:
属性没有使用规范的命名方式:在 Java 中,属性的命名方式应该采用驼峰命名法,即首字母小写,后面每个单词的首字母大写,例如 userId、userName 和 sex。
缺少 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,异常处理也相对比较完善。但还可以进一步改进,具体如下:
将 JdbcUtil 改为单例模式:JdbcUtil 是一个工具类,应该只有一个实例,所以将其改为单例模式可以避免在多线程环境下创建多个实例,并且可以减少数据库连接的开销。
使用 try-with-resources 语句:在调用 PreparedStatement 和 ResultSet 的 close() 方法时,可以使用 try-with-resources 语句,避免漏处理资源释放的情况。
参数校验和异常处理:对于参数值和查询结果是否为空等情况,可以进行参数校验和异常处理,确保代码的健壮性和安全性。
修改后的代码如下:
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 页面,主要是用于展示一个提交表单页面。但是在代码中存在一些问题:
缺少校验:代码没有对表单数据进行校验,可能会出现空值或不正确的数据导致的错误。
显式指定字符集:虽然页面设置了 contentType="text/html;charset=UTF-8",但最好还应该在头部添加 <%@page pageEncoding="UTF-8"%> 来显式指定字符集,以避免乱码问题。
注释问题:代码中的注释格式不规范,应统一使用 // 或 /* */ 标准的注释格式。
针对上述问题,修复后的代码如下:
【修复后的代码对表单数据进行了必填校验,指定了字符集,修正了注释格式,可以更好地 保障应用程序的正确性和可靠性。】
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 页面,主要是用于将表单数据插入到数据库中,并展示所有用户的信息列表。但是在代码中存在一些问题:
不应该在 JSP 中写 Java 代码:JSP 不应该用来写 Java 代码,而应该使用 JSP 中的标签和 EL 表达式等标准功能来展示数据。
数据库交互和业务逻辑不应该写在 JSP 中:这段代码中既包含了数据库操作(增)的代码,又包含了展示数据的代码,没有明确的分层和职责划分,会导致代码不易维护、不易测试等问题。
在页面中使用了注释:以下 // 转到 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.
这个代码主要是用于展示用户列表的信息,但是在代码中存在以下问题:
不应该在 JSP 中写 Java 代码:同样的,这段代码中也包含了 Java 代码,应该使用 JSP 标签和 EL 表达式来展示数据。
字段名不一致:代码中直接使用了 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 代码,大幅提高了代码的可读性和可维护性。