jsp-servlet(2)響應HTML文件-書籍管理系統
基礎知識預備:
目標:
構建一個書籍管理系統,並且部署到GitHub上。
功能:
1 安全註冊登入系統
2 圖書資訊查詢,(查)
3 書籍管理:入庫、出庫(增刪改)
4 安全退出系統
一、預備工作
Book{
Id,
Name,
Price,
Author,
Pubdate,
}
建表:
CREATE TABLE `book` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(50) CHARACTER SETutf8 COLLATE utf8_general_ci NULL DEFAULT NULL, `price` double NULL DEFAULT NULL, `author` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL, `pubDate` date NULL DEFAULT NULL, PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT =Dynamic; SET FOREIGN_KEY_CHECKS = 1;
二、書籍查詢功能
在java專案中新建實體類(Book類):放於cn.piggy.entity中
package cn.piggy.entity; import java.util.Date; public class Book { private int id; private String name; private double price; private String author; private Date pubDate;//需要三種構造方法:1無參的;2不帶id的,用於新增書籍時;3 帶有id的,用於查詢時 //1無參構造方法 public Book(){ } //2 不帶id public Book(String name, double price, String author, Date pubDate) { super(); this.name = name; this.price = price; this.author = author; this.pubDate = pubDate; } //3 帶有id public Book(int id, String name, double price, String author, Date pubDate) { super(); this.id = id; this.name = name; this.price = price; this.author = author; this.pubDate = pubDate; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public double getPrice() { return price; } public void setPrice(double price) { this.price = price; } public String getAuthor() { return author; } public void setAuthor(String author) { this.author = author; } public Date getPubDate() { return pubDate; } public void setPubDate(Date pubDate) { this.pubDate = pubDate; } @Override public String toString() { return "Book [id=" + id + ", name=" + name + ", price=" + price + ", author=" + author + ", pubDate=" + pubDate + "]"; } }
分析功能:先做顯示所有書籍的功能。
先做書籍查詢功能----
由於對於書籍的操作有很多:如查詢,修改,增加等與資料庫互動的操作。將它們放於一個類中,放於BookDao中。
建一個Dao包,該包下放所有與資料庫相關的操作。
由於需要與資料庫進行連線、返回結果等操作,所以寫了一個util的工具包,放於cn.piggy.util包中,其中有一個類叫做BaseDao.
BaseDao:載入jdbc驅動;實現資料庫連線和關閉連線;查詢,增刪改SQL語句的實現。
package cn.piggy.util; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; public class BaseDao { private Connection conn; private PreparedStatement ps; private ResultSet rs; //獲得連線 private void getConnection(){ try { Class.forName("com.mysql.jdbc.Driver");//載入MySQL的驅動,jar包放於webroot的lib目錄下 String url="jdbc:mysql://localhost:3306:/booksys";//booksys資料庫的地址,本地,3306埠 conn = DriverManager.getConnection(url,"root","qyzSQL"); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } } //關閉連線 public void close(){ if(rs!=null) try { rs.close(); } catch (SQLException e) { e.printStackTrace(); } if(ps!=null) try { ps.close(); } catch (SQLException e) { e.printStackTrace(); } if(conn!=null) try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } //更新--修改,增加,刪除 //sql=insert into book(name,price,author,pubDate) values(?,?,?,?),更新時只需要傳入這條sql語句即可 public int executeUpdate(String sql,Object...objects){//這裡objects是不定引數,需要查資料看一下是什麼 try { this.getConnection(); ps = conn.prepareStatement(sql); if(objects!=null)//設定四個引數 for(int i=0;i<objects.length;i++){ ps.setObject(i+1, objects[i]);//從1開始 } return ps.executeUpdate(); } catch (SQLException e) { e.printStackTrace(); }finally { this.close(); } return -1; } //查詢(查詢與前面三者不同) public ResultSet executeQuery(String sql,Object...objects){ try { this.getConnection(); ps = conn.prepareStatement(sql); if(objects!=null)//設定四個引數 for(int i=0;i<objects.length;i++){ ps.setObject(i+1, objects[i]);//從1開始 } return rs = ps.executeQuery(); } catch (SQLException e) { e.printStackTrace(); } return null; } }BaseDao
package cn.piggy.util; import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; public class BaseDao { private Connection conn; private PreparedStatement ps; private ResultSet rs; //獲得連線 private void getConnection(){ try { Class.forName("com.mysql.cj.jdbc.Driver");//載入MySQL的驅動,jar包放於webroot的lib目錄下 System.out.println("資料庫載入成功!"); String url="jdbc:mysql://localhost:3306/booksys?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&useSSL=false";//booksys資料庫的地址,本地,3306埠 conn = DriverManager.getConnection(url,"root","******"); System.out.println("連線成功,獲取連線物件: " + conn); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (SQLException e) { e.printStackTrace(); } } //關閉連線 public void close(){ if(rs!=null) try { rs.close(); } catch (SQLException e) { e.printStackTrace(); } if(ps!=null) try { ps.close(); } catch (SQLException e) { e.printStackTrace(); } if(conn!=null) try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } //更新--修改,增加,刪除 //sql=insert into book(name,price,author,pubDate) values(?,?,?,?),更新時只需要傳入這條sql語句即可 public int executeUpdate(String sql,Object...objects){//這裡objects是不定引數,需要查資料看一下是什麼 try { this.getConnection(); ps = conn.prepareStatement(sql); if(objects!=null)//設定四個引數 for(int i=0;i<objects.length;i++){ ps.setObject(i+1, objects[i]);//從1開始 } return ps.executeUpdate(); } catch (SQLException e) { e.printStackTrace(); }finally { this.close(); } return -1; } //查詢(查詢與前面三者不同) public ResultSet executeQuery(String sql,Object...objects){ try { this.getConnection(); ps = conn.prepareStatement(sql); if((ps!=null)&(objects!=null))//設定四個引數 for(int i=0;i<objects.length;i++){ ps.setObject(i+1, objects[i]);//從1開始 } return rs = ps.executeQuery(); } catch (SQLException e) { e.printStackTrace(); } return null; } }
BookDao:繼承自BaseDao,當具體的實體類(Book)需要與資料庫進行互動的時候,在BookDao中實現相應的查詢,增加,修改,刪除功能。
編寫ListServlet類
部署Servlet
1、500錯誤 顯示語句中BaseDao的第71行if(objects!=null)有NullException的錯誤。一開始以為是沒有判斷空指標。後來分析,出現空指標的原因是 01 mysql沒有連線上 02 資料庫是空的 一開始以為是載入jdbc驅動失敗的問題, 舊版本的驅動載入是這樣寫的: com.mysql.jdbc.Driver 新版本是這樣的: com.mysql.cj.jdbc.Driver 修改完以後,新增一條列印語句: Class.forName("com.mysql.cj.jdbc.Driver"); System.out.println("資料庫載入成功!"); 發現列印了該語句,說明並不是載入驅動失敗的問題。 然後檢查發現是URL寫錯了,booksys寫成了sysbook。 2 The server time zone value '???ú±ê×??±??' is unrecognized or represents more than one time zone. 出現這個的原因是因為 mysql返回的時間總是有問題,比實際時間要早8小時。 在jdbc連線的url後面加上serverTimezone=GMT即可解決問題,如果需要使用gmt+8時區,需要寫成GMT%2B8 public static final String URL="jdbc:mysql://localhost:3306/jdbc01?useUnicode=true&characterEncoding=utf8&serverTimezone=GMT%2B8&useSSL=false";//連結的mysql部署的時候出現的幾個問題
三、書籍新增功能
思路:新建add.html,完成圖書新增的操作(客戶端請求,表單以post方式提交);編寫AddServlet類,處理表單提交的資料,對get和post兩種提交方式,有對應的doGet和doPost兩種處理方式;獲得表單資料以後,編寫BookDao,將資料存到資料庫中。
新建add.html,完成圖書新增的操作。
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>add.html</title> <meta name="keywords" content="keyword1,keyword2,keyword3"> <meta name="description" content="this is my page"> <meta name="content-type" content="text/html; charset=UTF-8"> <!--<link rel="stylesheet" type="text/css" href="./styles.css">--> </head> <body> <form action="add" method="post"> <table width="80%" align="center"> <tr> <td colspan="2"><h3>新增書籍</h3>></td> </tr> <tr> <td>書名</td> <td><input type="text" name="name"/></td> </tr> <tr> <td>價格</td> <td><input type="text" name="price"/></td> </tr> <tr> <td>作者</td> <td><input type="text" name="author"/></td> </tr> <tr> <td>出版日期</td> <td><input type="text" name="pubDate"/></td> </tr> <tr> <td colspan="2" align="center"><input type="submit" name="提交"/></td> </tr> </table> </form> </body> </html>
這裡存在一個亂碼的問題待解決(已解決:Chrome沒有utf-8,外掛也不太方便安裝,轉用360瀏覽器後,編碼選擇utf-8就可以正常顯示了;更新:在add.html的head後增加
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>add.html</title>
即可解決問題)。
下面編寫AddServlet類,處理add.html提交的資料:HttpServletRequest有一個方法getParameter("fieldName"),可以獲取表單提交的資料(fieldName是表單的項)。
package cn.piggy.servlet; import java.io.IOException; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import cn.piggy.dao.BookDao; import cn.piggy.entity.Book; public class AddServlet extends HttpServlet{ private BookDao bookDao = new BookDao();//BookDao.java是一個類,需要new一個物件進行儲存 @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { req.setCharacterEncoding("utf-8"); //對亂碼進行處理 resp.setCharacterEncoding("utf-8"); String bookName = req.getParameter("name"); //HttpServletRequest獲取表單中fieldName的方法 //System.out.println("書名:"+bookName); double price = Double.parseDouble(req.getParameter("price"));//getParameter返回的是String型別,需要轉換一下 String author = req.getParameter("author"); Date pubDate = null; try { pubDate = new SimpleDateFormat("yyyy-MM-dd").parse(req.getParameter("pubDate")); //日期的格式轉換 } catch (ParseException e) { e.printStackTrace(); } Book book = new Book(bookName, price, author, pubDate); if(bookDao.add(book)>0){ // resp.setContentType("text/html;charset=utf-8"); // resp.getWriter().print("新增成功!! <a href='list'>查詢列表</>");//出現查詢列表按鈕,點選可以跳轉到“list”;還可以使用重定向方法 //重定向 resp.sendRedirect("list");//response物件的該函式可以重新定向到新增書籍後的狀態 }else{ resp.getWriter().print("新增失敗"); } } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doGet(req, resp); //當以post提交時,也採用get提交,以簡化操作 } }
在web.xml中增加程式碼,對AddServlet進行部署。
<servlet> <servlet-name>addServlet</servlet-name> <servlet-class>cn.piggy.servlet.AddServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>addServlet</servlet-name> <url-pattern>/add</url-pattern> </servlet-mapping>
在BookDao.java中新增一個查詢書籍的函式,通過新增SQL語句進行新增。
package cn.piggy.dao; import java.sql.ResultSet; import java.sql.SQLException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.List; import cn.piggy.entity.Book; import cn.piggy.util.BaseDao; public class BookDao extends BaseDao{ //查詢出所有書籍,放到一個List中 public List<Book> getAll(){ List<Book> list = new ArrayList<Book>(); String sql="select * from book"; //查詢的操作 try { ResultSet rs=this.executeQuery(sql); while(rs.next()){ list.add(new Book(rs.getInt(1),rs.getString(2),rs.getDouble(3), rs.getString(4),rs.getDate(5))); } } catch (SQLException e) { e.printStackTrace(); }finally{ this.close(); } return list; } public Book getById(int id){ String sql="select * from book where id=?"; //查詢的操作 try { ResultSet rs=this.executeQuery(sql,id); if(rs.next()){ return new Book(rs.getInt(1),rs.getString(2),rs.getDouble(3), rs.getString(4),rs.getDate(5)); } } catch (SQLException e) { e.printStackTrace(); }finally{ this.close(); } return null; } //新增書籍 public int add(Book b){ String sql = "insert into book(name,price,author,pubDate) values(?,?,?,?)"; return this.executeUpdate(sql, b.getName(),b.getPrice(),b.getAuthor(), new SimpleDateFormat("yyyy-MM-dd").format(b.getPubDate()));//b.getPubDate()直接傳入不行 } //修改書籍 public int update(Book b){ String sql="update book set name=?,price=?,author=?,pubDate=? where id=?"; return this.executeUpdate(sql,b.getName(),b.getPrice(),b.getAuthor(), new SimpleDateFormat("yyyy-MM-dd").format(b.getPubDate()),b.getId()); } //刪除書籍 public int delete(int id){ String sql = "delete from book where id=?"; return this.executeUpdate(sql, id); } }
四、書籍修改功能
package cn.piggy.servlet; import java.io.IOException; import java.io.PrintWriter; import java.text.SimpleDateFormat; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import cn.piggy.dao.BookDao; import cn.piggy.entity.Book; public class SelectByIdServlet extends HttpServlet { private BookDao bookDao = new BookDao(); @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 獲取id int id = 0; if(req.getParameter("id")!=null) id = Integer.parseInt(req.getParameter("id")); //根據id查詢對應記錄 Book book = bookDao.getById(id); resp.setCharacterEncoding("utf-8"); resp.setContentType("text/html;charset=utf-8"); PrintWriter out = resp.getWriter(); out.print("<html>"); out.print("<head>"); out.print("<title>書籍列表</title>"); out.print("</head>"); out.print("<body>"); out.print("<form action='update' method='post'>"); out.print("<table width='80%' align='center'>"); out.print("<tr><td colspan='2' align='center'>修改書籍</td></tr>"); out.print("<tr>"); out.print("<td>"); out.print("書名:<input type='hidden' name='id' value='"+book.getId()+"'/>"); out.print("</td>"); out.print("<td>"); out.print("<input type='text' name='name' value='"+book.getName()+"'/>"); out.print("</td>"); out.print("</tr>"); out.print("<tr>"); out.print("<td>"); out.print("價格"); out.print("</td>"); out.print("<td>"); out.print("<input type='text' name='price' value='"+book.getPrice()+"'/>"); out.print("</td>"); out.print("</tr>"); out.print("<tr>"); out.print("<td>"); out.print("作者"); out.print("</td>"); out.print("<td>"); out.print("<input type='text' name='author' value='"+book.getAuthor()+"'/>"); out.print("</td>"); out.print("</tr>"); out.print("<tr>"); out.print("<td>"); out.print("出版日期"); out.print("</td>"); out.print("<td>"); out.print("<input type='text' name='pubDate' value='"+book.getPubDate().toLocaleString()+"'/>"); out.print("</td>"); out.print("</tr>"); out.print("<tr>"); out.print("<td colspan='2' align='center'>"); out.print("<input type='submit' value='修改'/>"); out.print("</td>"); out.print("</tr>"); out.print("</table>"); out.print("</form>"); out.print("</body>"); out.print("</html>"); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // TODO Auto-generated method stub this.doGet(req, resp); } }
package cn.piggy.servlet; import java.io.IOException; import java.io.PrintWriter; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import cn.piggy.dao.BookDao; import cn.piggy.entity.Book; public class UpdateServlet extends HttpServlet { private BookDao bookDao = new BookDao();//BookDao.java是一個類,需要new一個物件進行儲存 @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { req.setCharacterEncoding("utf-8"); //對亂碼進行處理 resp.setCharacterEncoding("utf-8"); int id = 0; if(req.getParameter("id")!=null) id = Integer.parseInt(req.getParameter("id")); String bookName = req.getParameter("name"); //HttpServletRequest獲取表單中fieldName的方法 //System.out.println("書名:"+bookName); double price = Double.parseDouble(req.getParameter("price"));//getParameter返回的是String型別,需要轉換一下 String author = req.getParameter("author"); Date pubDate = null; try { pubDate = new SimpleDateFormat("yyyy-MM-dd").parse(req.getParameter("pubDate")); //日期的格式轉換 } catch (ParseException e) { e.printStackTrace(); } Book book = new Book(id,bookName,price,author,pubDate); System.out.println(book); if(bookDao.update(book)>0){ // resp.setContentType("text/html;charset=utf-8"); // resp.getWriter().print("新增成功!! <a href='list'>查詢列表</>");//出現查詢列表按鈕,點選可以跳轉到“list”;還可以使用重定向方法 //重定向 resp.sendRedirect("list");//response物件的該函式可以重新定向到新增書籍後的狀態 }else{ resp.getWriter().print("修改失敗"); } } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { this.doGet(req, resp); //當以post提交時,也採用get提交,以簡化操作 } }
package cn.piggy.servlet; import java.io.IOException; import java.io.PrintWriter; import java.text.SimpleDateFormat; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import cn.piggy.dao.BookDao; import cn.piggy.entity.Book; public class SelectByIdServlet extends HttpServlet { private BookDao bookDao = new BookDao(); @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // 獲取id int id = 0; if(req.getParameter("id")!=null) id = Integer.parseInt(req.getParameter("id")); //根據id查詢對應記錄 Book book = bookDao.getById(id); resp.setCharacterEncoding("utf-8"); resp.setContentType("text/html;charset=utf-8"); PrintWriter out = resp.getWriter(); out.print("<html>"); out.print("<head>"); out.print("<title>書籍列表</title>"); out.print("</head>"); out.print("<body>"); out.print("<form action='update' method='post'>"); out.print("<table width='80%' align='center'>"); out.print("<tr><td colspan='2' align='center'>修改書籍</td></tr>"); out.print("<tr>"); out.print("<td>"); out.print("書名:<input type='hidden' name='id' value='"+book.getId()+"'/>"); out.print("</td>"); out.print("<td>"); out.print("<input type='text' name='name' value='"+book.getName()+"'/>"); out.print("</td>"); out.print("</tr>"); out.print("<tr>"); out.print("<td>"); out.print("價格"); out.print("</td>"); out.print("<td>"); out.print("<input type='text' name='price' value='"+book.getPrice()+"'/>"); out.print("</td>"); out.print("</tr>"); out.print("<tr>"); out.print("<td>"); out.print("作者"); out.print("</td>"); out.print("<td>"); out.print("<input type='text' name='author' value='"+book.getAuthor()+"'/>"); out.print("</td>"); out.print("</tr>"); out.print("<tr>"); out.print("<td>"); out.print("出版日期"); out.print("</td>"); out.print("<td>"); out.print("<input type='text' name='pubDate' value='"+book.getPubDate().toLocaleString()+"'/>"); out.print("</td>"); out.print("</tr>"); out.print("<tr>"); out.print("<td colspan='2' align='center'>"); out.print("<input type='submit' value='修改'/>"); out.print("</td>"); out.print("</tr>"); out.print("</table>"); out.print("</form>"); out.print("</body>"); out.print("</html>"); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { // TODO Auto-generated method stub this.doGet(req, resp); } }
難點:
out.print("<td>");
out.print("書名:<input type='hidden' name='id' value='"+book.getId()+"'/>");
out.print("</td>");
在SelectByIdServlet中,建立了一個表單,其中不需要顯示Id。該表單向伺服器提交請求。
伺服器收到請求以後,在UpdateServlet中響應。UpdateServlet需要獲取Id的值,所以有了上述程式碼。‘hidden’引數:請求中既提交了id的資訊,又不會在表單中顯示id。
五、最終效果:
六、附錄:
知識點(包括筆記):
1 DAO:data access object資料訪問物件
2 HttpServletResponse物件
3 HttpServletRequest物件
注:http協議的小知識:
客戶端:瀏覽器;服務端:Tomcat伺服器
如果表單是get提交,所提交的引數是跟在URL後的,以?name=value&price=23這樣的方式追加在URL後。特點:長度有限;不安全;效率相對較高。
如果表單是post提交,那麼資料將被封裝在formdata裡面。特點:長度沒有限制;安全性高;效率相對低。
HttpServletRequest有一個方法getParameter("fieldName"),可以獲取表單提交的資料(fieldName是表單的項)。
4 重定向與轉發
由response.sendRedirect("list") 實現,當使用重定向時,伺服器會將重新定向的地址(“list”)交給瀏覽器,瀏覽器會根據新的URL,重新發起請求。
5 JDBC
Java 資料庫連線,(Java Database Connectivity,簡稱JDBC)是Java語言中用來規範客戶端程式如何來訪問資料庫的應用程式介面,提供了諸如查詢和更新資料庫中資料的方法。
簡單地說,就是用於執行SQL語句的一類Java API
Base.Dao中:
public ResultSet executeQuery(String sql,Object...objects){ } //在java中實現query(查詢)SQL語句 java.sql.ResultSet型別包含從資料庫中查詢的結果集
public int executeUpdate(String sql,Object...objects){
} //在java中實現Update(增刪改)SQL語句
6 書籍管理系統中的難點分析