bug修復(fù)
前面我們的項目中,Blog類和User類的id屬性設(shè)置為long類型豹障,實際上應(yīng)該設(shè)置為Long類型會更好描睦。因為:
- Java中Long 類型建立的時候如果沒賦值,會默認(rèn)給一個null.而long類型建立的時候如果沒有賦值判哥,則是0L。而id屬性是數(shù)據(jù)庫自動去填充值的碉考,不應(yīng)該有默認(rèn)值塌计,我們可以通過是否為null來判斷是否存在記錄。
- Long提供了很多API雨效, 比如查詢蛤高、賦空值等簡便撵彻, 可以利用Long本身的優(yōu)化;如你使用Long.valueOf時 可以利用緩存的-128至127之間的值热芹; 還有從使用hibernate、el表達(dá)式等都是包裝類型嫩痰,減少了裝箱/拆箱剿吻;
我們還得修改模型類的getId、setId的返回類型串纺。
同理丽旅,模型類比如購物車Cart,它的字段頁應(yīng)該是Integer而不是int纺棺。相應(yīng)的我們要修改那些傳入?yún)?shù)long參數(shù)對應(yīng)的修改為Long才行榄笙。一般模型類中的方法參數(shù)最好都是封裝類型而不是基本類型。
model類里面去掉id = count++;
因為id自增交由數(shù)據(jù)庫去完成祷蝌,所以我們不必使用java代碼去實現(xiàn)茅撞。所以我們要去修改User模型類和Blog模型類。
User模型類需要添加新的字段description
相應(yīng)的修改用戶倉庫初始化代碼和用戶模型類構(gòu)造器
數(shù)據(jù)庫通用操作封裝到DBHleper工具類
package com.jspblog.utils;
import com.jspblog.model.Blog;
import com.jspblog.model.Project;
import com.jspblog.model.User;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;
public class DBHelper {
public static String driver = "com.mysql.jdbc.Driver";
public static String connectionString = "jdbc:mysql://127.0.0.1:3306/jspblog?useSSL=false";
public static String username = "root";
public static String password = "123456";
// 1巨朦、加載MYSQL驅(qū)動米丘,這里MySQL的JDBC驅(qū)動類是com.mysql.jdbc.Driver,要求類路徑中包含相應(yīng)的Driver類
static {
try {
Class.forName(driver).newInstance();
} catch (InstantiationException | IllegalAccessException | ClassNotFoundException e) {
e.printStackTrace();
}
}
// 2糊啡、連接到MYSQL拄查,通過DriverManger來創(chuàng)建Connection對象,獲取數(shù)據(jù)庫連接
public static Connection getConnection() throws Exception {
return DriverManager.getConnection(connectionString, username, password);
}
// 3棚蓄、創(chuàng)建PreparedStatement用以執(zhí)行SQL語句
// 插入操作堕扶,我們希望獲得插入記錄后的編號,也就是返回值是id
public static Long create(String sql) {
Connection connection = null;
PreparedStatement statement = null;
ResultSet resultSet = null;
try {
//2,連接到MYSQL
connection = getConnection();
//3梭依,PreparedStatement用以執(zhí)行SQL語句
statement = connection.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
statement.executeUpdate();
//4稍算,ResultSet用于接收SQL語句執(zhí)行后的結(jié)果,更新之后我們只需要獲取更新記錄的id屬性即可役拴,而不是整個記錄對象
resultSet = statement.getGeneratedKeys();
//5糊探、遍歷并解析結(jié)果
if (resultSet.next()) {
return resultSet.getLong(1);
}
return null;
} catch (Exception e) {
e.printStackTrace();
return null;
} finally {
//6,清理數(shù)據(jù)庫連接相關(guān)的所有資源
clear(resultSet, statement, connection);
}
}
// 刪除操作,用于remove動作
// 由于刪除之后就不存在就該記錄了侧到,所以不需要遍歷結(jié)果頁不用返回id勃教,直接返回數(shù)字0表示刪除成功
public static int delete(String sql) {
Connection connection = null;
PreparedStatement statement = null;
try {
connection = DBHelper.getConnection();
statement = connection.prepareStatement(sql);
return statement.executeUpdate();
} catch (Exception e) {
e.printStackTrace();
return 0;
} finally {
clear(null, statement, connection);
}
}
//查詢單條記錄,查詢就應(yīng)該返回對象匠抗,而不像插入那樣只要返回id故源。由于查詢的可能是不同對象,所以使用泛型
public static Blog queryBlog(String sql) {
Connection connection = null;
PreparedStatement statement = null;
ResultSet resultSet = null;
try {
connection = DBHelper.getConnection();
statement = connection.prepareStatement(sql);
resultSet = statement.executeQuery();
if (resultSet.first()) {
int userId = resultSet.getInt("author");
User user = queryUser("select * from user where id="+userId);
Blog blog = new Blog(resultSet.getString("title"),resultSet.getString("content"),resultSet.getDate("createdTime"),user);
return blog;
}
return null;
} catch (Exception e) {
e.printStackTrace();
return null;
} finally {
clear(null, statement, connection);
}
}
//查詢單條記錄汞贸,查詢就應(yīng)該返回對象绳军,而不像插入那樣只要返回id。由于查詢的可能是不同對象矢腻,所以使用泛型
public static User queryUser(String sql) {
Connection connection = null;
PreparedStatement statement = null;
ResultSet resultSet = null;
try {
connection = DBHelper.getConnection();
statement = connection.prepareStatement(sql);
resultSet = statement.executeQuery();
if (resultSet.first()) {
User user = new User(resultSet.getString("email"),resultSet.getString("username"),resultSet.getString("password"));
return user;
}
return null;
} catch (Exception e) {
e.printStackTrace();
return null;
} finally {
clear(null, statement, connection);
}
}
//查詢單條記錄门驾,查詢就應(yīng)該返回對象,而不像插入那樣只要返回id多柑。由于查詢的可能是不同對象奶是,所以使用泛型
public static Project queryProject(String sql) {
Connection connection = null;
PreparedStatement statement = null;
ResultSet resultSet = null;
try {
connection = DBHelper.getConnection();
statement = connection.prepareStatement(sql);
resultSet = statement.executeQuery();
if (resultSet.first()) {
Project project = new Project(resultSet.getString("name"),resultSet.getString("description"),resultSet.getString("url"),resultSet.getString("logo"));
return project;
}
return null;
} catch (Exception e) {
e.printStackTrace();
return null;
} finally {
clear(null, statement, connection);
}
}
//查詢多條記錄,與查詢單條記錄不同在于是遍歷結(jié)果集放入數(shù)組中。由于查詢的可能是不同對象竣灌,所以使用泛型
@SuppressWarnings("unchecked")
public static List<Blog> queryBlogList(String sql) {
Connection connection = null;
PreparedStatement statement = null;
ResultSet resultSet = null;
try {
List<Blog> list = new ArrayList<Blog>();
connection = DBHelper.getConnection();
statement = connection.prepareStatement(sql);
resultSet = statement.executeQuery();
while(resultSet.next()) {
int userId = resultSet.getInt("author");
User user = queryUser("select * from user where id="+userId);
Blog blog = new Blog(resultSet.getString("title"),resultSet.getString("content"),resultSet.getDate("createdTime"),user);
list.add(blog);
}
return list;
} catch (Exception e) {
e.printStackTrace();
return null;
} finally {
clear(null, statement, connection);
}
}
//查詢多條記錄,與查詢單條記錄不同在于是遍歷結(jié)果集放入數(shù)組中聂沙。由于查詢的可能是不同對象,所以使用泛型
@SuppressWarnings("unchecked")
public static List<Project> queryProjectList(String sql) {
Connection connection = null;
PreparedStatement statement = null;
ResultSet resultSet = null;
try {
List<Project> list = new ArrayList<Project>();
connection = DBHelper.getConnection();
statement = connection.prepareStatement(sql);
resultSet = statement.executeQuery();
while(resultSet.next()) {
Project project = new Project(resultSet.getString("name"),resultSet.getString("description"),resultSet.getString("url"),resultSet.getString("logo"));
list.add(project);
}
return list;
} catch (Exception e) {
e.printStackTrace();
return null;
} finally {
clear(null, statement, connection);
}
}
//查詢多條記錄,與查詢單條記錄不同在于是遍歷結(jié)果集放入數(shù)組中初嘹。由于查詢的可能是不同對象及汉,所以使用泛型
@SuppressWarnings("unchecked")
public static List<User> queryUserList(String sql) {
Connection connection = null;
PreparedStatement statement = null;
ResultSet resultSet = null;
try {
List<User> list = new ArrayList<User>();
connection = DBHelper.getConnection();
statement = connection.prepareStatement(sql);
resultSet = statement.executeQuery();
while(resultSet.next()) {
User user = new User(resultSet.getString("email"),resultSet.getString("username"),resultSet.getString("password"),resultSet.getString("description"));
list.add(user);
}
return list;
} catch (Exception e) {
e.printStackTrace();
return null;
} finally {
clear(null, statement, connection);
}
}
// 計數(shù)
//技術(shù)我們一般傳入sql語句是select count(*)這樣的語句,返回結(jié)果只有一條記錄屯烦,頁只有一個字段坷随。該字段存的就是count的記錄數(shù)目
public static int queryCount(String sql) {
Connection connection = null;
PreparedStatement statement = null;
ResultSet resultSet = null;
try {
connection = DBHelper.getConnection();
statement = connection.prepareStatement(sql);
resultSet = statement.executeQuery();
//由于結(jié)果肯定只有一條記錄,所以我們?nèi)〕鰂irst結(jié)果即可
if (resultSet.first()) {
return resultSet.getInt(1); //獲取結(jié)果集中第一列的值驻龟,count語句返回的本來就只有一個字段
}
return 0;
} catch (Exception e) {
e.printStackTrace();
return 0;
} finally {
clear(null, statement, connection);
}
}
//6温眉、清理數(shù)據(jù)庫連接相關(guān)的所有資源
private static void clear(ResultSet resultSet, Statement statement, Connection connection) {
try {
if (resultSet != null) {
resultSet.close();
}
if (statement != null) {
statement.close();
}
if (connection != null) {
connection.close();
}
} catch (SQLException ignored) {
}
}
}
Statement.RETURN_GENERATED_KEYS用于獲取自動生成的鍵值,這里是自增的id號翁狐。這里也就是我們不必給數(shù)據(jù)庫對象的id屬性賦值芍殖,在執(zhí)行sql語句的時候,添加該代碼會自動往記錄的id自動填入一個自動增長的數(shù)字谴蔑。
getGeneratedKeys();用于獲取主鍵,也就是上面我們執(zhí)行插入語句時龟梦,自動填充的id字段的值隐锭。
新建數(shù)據(jù)庫表project
執(zhí)行語句如下:
CREATE TABLE `project` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`description` longtext NOT NULL,
`url` varchar(255) NOT NULL,
`logo` varchar(255) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
保持原Servlet不變,修改模型類
比如我們ProjectRepository類中的getAll方法:
public List<Project> getAll() {
return projects;
}
應(yīng)該修改為:
public List<Project> getAll() {
return DBHelper.queryProjectList("select * from project");
}
因為Servlet獲取數(shù)據(jù)是去調(diào)用模型類中的方法而已计贰,而獲取數(shù)據(jù)修改為從數(shù)據(jù)庫中讀取也是把模型類中獲取的數(shù)據(jù)的方法體修改為調(diào)用DBHelper執(zhí)行sql語句而已钦睡。在Servlet中調(diào)用的模型類方法不變,變更的是模型類方法的實現(xiàn)躁倒,所以自然不需要修改Servlet文件荞怒。
而且private static List<Project> projects = new ArrayList<>();屬性也可以去掉了洒琢。因為之前沒有數(shù)據(jù)庫,所以使用一個數(shù)組屬性來保存多個對象褐桌,比如我們要獲取所有項目信息就去訪問這個數(shù)組屬性∷ヒ郑現(xiàn)在有了數(shù)據(jù)庫之后,要獲取所有項目信息只要調(diào)用getAll()方法荧嵌,得到的返回值就是一個包含所有項目信息的數(shù)組呛踊,我們直接使用方法的返回值就行,就不需要該數(shù)組屬性了啦撮。
其他方法比如User谭网、Blog等相關(guān)的多個類也做這樣的修改,模型類中獲取數(shù)據(jù)都改成使用DBHelper類從數(shù)據(jù)庫獲取數(shù)據(jù)赃春,去掉數(shù)組屬性愉择。
修改jsp文件里面引入類的包名,由mvc改為jspblog
把模型類中的數(shù)據(jù)初始化代碼刪除掉织中,通過Navicate在數(shù)據(jù)庫中錄入數(shù)據(jù)
把在WEB-INF/lib目錄里面放入數(shù)據(jù)庫驅(qū)動的jar包mysql-connector-java-5.1.40-bin.jar
必須完成上面全部的修改后锥涕,項目才能運行。
使用JDBC先完成創(chuàng)建博客抠璃、博客列表站楚、博客詳情三個功能與數(shù)據(jù)庫交互
到此,就完成了博客項目使用JDBC與數(shù)據(jù)庫交互的全部改寫搏嗡,測試通過窿春。
提交到git倉庫
創(chuàng)建.gitignore文件,由于我們之前使用oschina自動創(chuàng)建的.gitignore文件采盒,所以修改該文件后還是無法生效旧乞,應(yīng)該執(zhí)行下面操作清除一下緩存cache,才能使修改后的.gitignore 生效磅氨。
git rm -r --cached . #清除緩存
git add . #重新trace file
git commit -m "update .gitignore尺栖,(四)04-使用JDBC重寫博客項目" #提交和注釋
git push git@git.oschina.net:michael-first/jdbcblog.git master --force
為了以后提交方便,我們添加如下代碼烦租,以后提交的時候就使用jdbcblog替換代碼倉庫的地址延赌,很方便
git remote add jdbcblog git@git.oschina.net:michael-first/jdbcblog.git
git push jdbcblog master