Copyright © 2020 Linyer. All Rights Reserved.
目錄
初識JSP
JSP 輸出 和 註釋
- Java代碼寫在
<% %>
裏面,稱爲Java小腳本。 - 設置 JSP 頁面屬性:
<%@ page %>
- 在頁面輸出一句話:
<% out.print("<h1>Java Web 筆記!</h1>"); %>
- 變量輸出:
<% String head = "Java Web 筆記!" %>
<h1><%=head%></h1>
- HTML 註釋:
<!-- html註釋 -->
- JSP 註釋:
<%-- out.print("<h1>Java Web 筆記!</h1>"); --%>
- JSP 中腳本註釋:
<%
//單行註釋!
/*多行註釋!*/
%>
JSP 中使用變量
<%@ page import="java.text.SimpleDateFormat" %>
<%
String title = "Java Web 筆記!";
//當前系統時間
Date date = new Date();
//格式化輸出時間
SimpleDateFormat fromater = new SimpleDateFormat("yyyy-MM-dd");
String time = fromater.format(date);
%>
<h1><%=title %></h1>
<h1>當前時間爲:<%=time %></h1>
JSP 聲明全局變量 和 方法
- 全局變量每刷新一次都加1
<h1><%=title %></h1>
當前時間爲:<%=time %>
<%
//局部變量
int i = 2;
%>
<h1><%=i++ %></h1>
<%!
//全局變量
int j = 6;
%>
<h1><%=j++ %></h1>
- 方法要寫全局形式
<%!
public int add() {
return 8+8;
}
%>
<%=add() %>
Web 程序的錯誤
- 404 錯誤:找不到訪問的頁面或資源。
- 500 錯誤:JSP頁面語法有誤。
JSP 實現 數據傳遞 和 保存
獲取請求中的數據
- 發送請求頁面 Regist.jsp
- 外面包上
<form></form>
發送數據
- 外面包上
<h1 align="center"><font color="green">用戶註冊</font></h1>
<form name="registerFrm" id="registFrm" action="doRegist.jsp" method="get">
<table class="tb" border="0" cellspacing="5" cellpadding="0" align="center">
<tr>
<td class="text_tabledatil2">用戶名</td>
<td><input type="text" name="username"/></td>
</tr>
<tr>
<td class="text_tabledatil2">密碼</td>
<td><input type="password" name="password"/></td>
</tr>
<tr>
<td class="text_tabledatil2">確認密碼</td>
<td><input type="password" name="con_password"/></td>
</tr>
<tr>
<td class="text_tabledatil2">e-mail</td>
<td><input type="text" name="email"/></td>
</tr>
<tr>
<td class="text_tabledatil2">愛好</td>
<td>
<input type="checkbox" name="hobby" value="游泳"/>游泳<br/>
<input type="checkbox" name="hobby" value="閱讀"/>閱讀<br/>
<input type="checkbox" name="hobby" value="爬山"/>爬山<br/>
<input type="checkbox" name="hobby" value="旅遊"/>旅遊<br/>
</td>
</tr>
<tr>
<td style="text-align:center" colspan="2">
<button type="submit" class="page-btn" name="save">註冊</button>
</td>
</tr>
</table>
</form>
- 方法:
public String getParameter(String name)
- 接受請求頁面 doRegist.jsp
<%
String userName = request.getParameter("username");
String pwd = request.getParameter("password");
String email = request.getParameter("email");
String[] hobby = request.getParameterValues("hobby");
%>
用戶名:<%=userName %><br/>
密碼 :<%=pwd %><br/>
email:<%=email %><br/>
用戶愛好:
<%
if(hobby!=null&&hobby.length!=0){
for(String hobbys:hobby){
out.print(hobbys+" ");
}
}else{
out.print("沒選愛好!");
}
%>
轉發 與 重定向
- request 的作用域:一次請求
- 保存屬性方法:
public void setAttribute(String name,Object o)
要對 name 做非空判斷!
- 獲取屬性方法:
public Object getAttribute(String name)
- 轉發:使用 RequestDispatcher 對象中的 forward() 方法
request.getRequestDispatcher("url").forward(request,response)
- 重定向:將用戶請求重新定位到一個新的 URL
request.sendRedirect("url")
- 轉發與重定向的區別
比較項目 | 轉發 | 重定向 |
---|---|---|
URL 變化 | 否 | 是 |
重新發出請求 | 不會 | 會 |
是否攜帶請求 | 是 | 否 |
目標 URL 要求 | 僅本 Web 應用 | 任意 URL |
- doRegist.jsp
if(!pwd.equals(c_pwd)) {
request.setAttribute("mess","兩次輸入密碼不一致,註冊失敗!");
request.getRequestDispatcher("Regist.jsp").forward(request, response);
}else{
String info = "sucess";
response.sendRedirect("index.jsp?info="+info);
}
- Regist.jsp
Object omess = request.getAttribute("mess");
if(omess!=null){
out.print(omess.toString());
}
- index.jsp
if(request.getParameter("info").equals("sucess")){
out.print("<h1 align=\"center\"><font color=\"green\">恭喜你!註冊成功!</font></h1>");
}
JSP 內置對象
- JSP 已經準備好的,可以直接使用的對象
對象 | 語句 |
---|---|
請求對象 | request |
輸出對象 | out |
響應對象 | response |
應用程序對象 | application |
會話對象 | session |
頁面上下文對象 | pageContext |
頁面對象 | page |
配置對象 | config |
異常對象 | exception |
session 的使用
- session 作用域:一次會話
- 會話:一個會話就是瀏覽器和服務器之間的一次通話
- 會話 可以在多次請求中保存和使用數據
- 修改 doRegister.jsp 中 else 後面爲:
else{
session.setAttribute("userName",userName);
response.sendRedirect("index.jsp");
}
會話的 清除 和 過期
程序主動清除 session 數據
- 設置會話失效:
session.invalidate();
- 移除會話的一個屬性:
public void remoteAttribute(String name);
- 用法:
session.remoteAttribute("userNmae");
服務器主動清除長時間沒有再次發出請求的 session
- 設置會話過期時間:
- 方法一:
public void setMaxInactiveInterval(int interval);
設置最大活動時間,單位爲 秒!
- 方法二:
<session-config>
<session-timeout>30</session-timeout>
</session-config>
- 單位爲 分鐘
- 在
web.xml
中設置!
- Loginout.jsp
//用戶註銷會話
session.invalidate();
response.sendRedirect("index.jsp");
cookie 的使用
- cookie:跟蹤用戶的整個會話
- 在客戶端記錄信息,給客戶端發送一個通行證,每個客戶一個。
- 本質是一小段文本信息。
- 以文件的形式保存數據。
- 添加數據
public void addCookie(Cookie cookie);
- 獲取數據
public Cookie[] getCookie();
- 設置路徑
cookie.setPath("/");
- 整個工程無論什麼路徑都能訪問 cookie
- session 基於 cookie
utf-8
中文 編碼 解碼
userName = URLEncoder.encode(userName,"utf-8");
userName = URLDecoder.decode(userName,"utf-8");
- doRegist.jsp
Cookie cookie = new Cookie("userName",userName);
cookie.setMaxAge(60*60);
response.addCookie(cookie);
application 的使用
- application 作用域:整個應用程序
- 統計頁面訪問次數
//統計該頁面的訪問次數
Object count = application.getAttribute("count");
if(count==null){
//第一次訪問
application.setAttribute("count", 1);
}else{
//非第一次訪問
Integer i = (Integer)count;
application.setAttribute("count", i+1);
}
Integer icount = (Integer)application.getAttribute("count");
out.print("訪問次數爲:"+icount);
三個對象對比
- request、session、application
- 相同點:都可以存儲屬性
- 不同點:
- request 中存儲的數據僅在一個請求中可用
- session 中存儲的數據在一個會話的有效期內可用
- application 中存儲的數據在整個Web項目中可用
使用 JDBC 操作數據庫
JDBC 使用步驟
- JDBC API
- 實現 Java 程序對各種數據庫的訪問
- 一組接口和類,位於 java.sql 與 javax.sql 包
- 面向接口編程
- JDBC 步驟固定!
- Class.forName(String) 加載驅動
- DriverManage 獲取 Connection 連接
- 創建 Statemen 或 PrepardStatement 對象執行 SQL 語句
- 返回 ResultSet 查詢結果
- 釋放資源(先用先關,後用後關)
使用 JDBC 實現查詢
- 查詢新聞 id、標題
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import com.mysql.jdbc.Connection;
import com.mysql.jdbc.Statement;
public class NewsDao {
//查詢新聞id、標題
public static void main(String[] args) {
//寫在外面,可以在finally裏關
Connection connection = null;
Statement stmt = null;
ResultSet rs = null;
try {
//Class.forName(String) 加載驅動
Class.forName("com.mysql.jdbc.Driver");
//DriverManage 獲取 Connection 連接
String url = "jdbc:mysql://localhost:9988/kgcnews?characterEncoding=utf8&useSSL=true";
connection = (Connection) DriverManager.getConnection(url,"root","123456");
// SQL 語句
String sql = "select id,title from news_detail;";
//創建 Statemen對象執行 SQL 語句
stmt = (Statement)connection.createStatement();
//返回 ResultSet 查詢結果
rs = stmt.executeQuery(sql);
while (rs.next()) {
int id = rs.getInt("id");
String title = rs.getString("title");
System.out.println(id+"\t"+title);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} finally {
//釋放資源
try {
rs.close();
stmt.close();
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
使用 PrepardStatement
- Statement 與 PreparedStatement 區別
- PreparedStatement 接口繼承 Statement
Statement st = connection.createStatement();
PrepareStatement pstm = connection.prepareStatement(sql);
-
SQL語句使用 “?” 作爲數據佔位符
使用 setXxx() 方法設置數據 - PreparedStatement——預編譯
- 效率、性能、開銷
- 安全性(PreparedStatement可以防止一定的SQL注入)
- 代碼可讀性
- 查詢特定標題的新聞信息
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import com.mysql.jdbc.Connection;
import com.mysql.jdbc.PreparedStatement;
public class NewsDao {
//查詢特定標題的新聞信息
public void getNewsByTitle(String title){
//寫在外面,可以在finally裏關
Connection connection = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
//Class.forName(String) 加載驅動
Class.forName("com.mysql.jdbc.Driver");
//DriverManage 獲取 Connection 連接
String url = "jdbc:mysql://localhost:9988/kgcnews?characterEncoding=utf8&useSSL=true";
connection = (Connection) DriverManager.getConnection(url,"root","123456");
// SQL 語句,?叫佔位符
String sql = "select * from news_detail where title=?";
//創建PreparedStatement對象執行 SQL 語句
pstmt = (PreparedStatement) connection.prepareStatement(sql);
//在sql語句的第一個問號的位置填充title
pstmt.setString(1, title);
//返回 ResultSet 查詢結果,不用再傳sql了
rs = pstmt.executeQuery();
while (rs.next()) {
int id = rs.getInt("id");
String newsTitle = rs.getString("title");
System.out.println(id+"\t"+newsTitle);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
} finally {
//釋放資源
try {
rs.close();
pstmt.close();
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
NewsDao dao = new NewsDao();
dao.getNewsByTitle("Java Web開課啦");
}
}
實現數據 增刪改 操作
- 示例:
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.Date;
import com.mysql.jdbc.Connection;
import com.mysql.jdbc.PreparedStatement;
//用 JDBC 實現新聞數據 增 刪 改 操作
public class NewsDao{
Connection connection = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
//獲取數據庫連接
public void getConnection(){
try {
Class.forName("com.mysql.jdbc.Driver");
String url = "jdbc:mysql://localhost:9988/kgcnews?characterEncoding=utf8&useSSL=true";
connection = (Connection) DriverManager.getConnection(url,"root","123456");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}catch (SQLException e) {
e.printStackTrace();
}
}
//關閉數據庫連接
public void closeConection(){
try {
pstmt.close();
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
//增加新聞信息
public void addNews(int id,int categoryid,String title,String summary,String content,String author,Date createdate){
try {
this.getConnection();
String sql = "INSERT INTO news_detail(id,categoryid,title,summary,content,author,createdate) VALUES(?,?,?,?,?,?,?)";
pstmt = (PreparedStatement) connection.prepareStatement(sql);
pstmt.setInt(1,id);
pstmt.setInt(2,categoryid);
pstmt.setString(3,title);
pstmt.setString(4,summary);
pstmt.setString(5,content);
pstmt.setString(6,author);
pstmt.setTimestamp(7, new Timestamp(createdate.getTime()));
int i = pstmt.executeUpdate();
if(i > 0){
System.out.println("插入新聞成功!");
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
this.closeConection();
}
}
//刪除特定新聞標題
public void deleteNews(int id){
try {
this.getConnection();
String sql = "DELETE FROM news_detail WHERE id=?";
pstmt = (PreparedStatement) connection.prepareStatement(sql);
pstmt.setInt(1, id);
int i = pstmt.executeUpdate();
if(i > 0){
System.out.println("刪除新聞成功!");
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
this.closeConection();
}
}
//修改特定新聞標題的方法
public void updateNews(int id,String title){
try {
this.getConnection();
String sql = "UPDATE news_detail SET title=? WHERE id=?";
pstmt = (PreparedStatement) connection.prepareStatement(sql);
pstmt.setString(1, title);
pstmt.setInt(2, id);
int i = pstmt.executeUpdate();
if(i > 0){
System.out.println("修改新聞成功!");
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
this.closeConection();
}
}
//查詢全部新聞信息
public void getNewsList(String title){
try {
this.getConnection();
String sql = "select id,categoryid,title,summary,content,author,createdate from news_detail";
pstmt = (PreparedStatement) connection.prepareStatement(sql);
rs = pstmt.executeQuery();
while (rs.next()) {
int id = rs.getInt("id");
int categoryid = rs.getInt("categoryid");
String newsTitle = rs.getString("title");
String summary = rs.getString("summary");
String content = rs.getString("content");
String author = rs.getString("author");
Timestamp createdate = rs.getTimestamp("createdate");
System.out.println(id+"\t"+categoryid+"\t"+newsTitle+"\t"+summary+"\t"+content+"\t"+author+"\t"+createdate);
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
this.closeConection();
}
}
//查詢特定標題的新聞信息
public void getNewsByTitle(String title){
try {
this.getConnection();
String sql = "select * from news_detail where title=?";
//創建PreparedStatement對象執行 SQL 語句
pstmt = (PreparedStatement) connection.prepareStatement(sql);
//在sql語句的第一個問號的位置填充title
pstmt.setString(1, title);
//返回 ResultSet 查詢結果,不用再傳sql了
rs = pstmt.executeQuery();
while (rs.next()) {
int id = rs.getInt("id");
String newsTitle = rs.getString("title");
System.out.println(id+"\t"+newsTitle);
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
//釋放資源
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
this.closeConection();
}
}
public static void main(String[] args) {
NewsDao dao = new NewsDao();
// dao.addNews(3, 1, "test", "test", "test", "Linyer", new Date());
// dao.deleteNews(3);
// dao.updateNews(3, "newTitle");
// dao.getNewsList("Java Web開課啦");
dao.getNewsByTitle("Java Web開課啦");
}
}
DAO 模式 及 單例模式
DAO 組件的優化思路
- 操作:
- 提取數據庫公共操作(獲取數據庫連接、釋放資源、增刪改、查)形成一個數據庫操作的基類。
- 將 NewsDao 提取一個穩定的新聞操作的接口,新聞操作寫在接口的實現類中。
- 作用:
- 將相似功能的代碼抽取封裝成方法,減少代碼冗餘。
- 因爲不同的數據庫會有不同的實現,對數據庫的操作一般抽取成接口,在以後的開發中可以降低耦合。
DAO 操作的基類
- BaseDao.java 示例(放在dao包中):
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import com.mysql.jdbc.Connection;
import com.mysql.jdbc.PreparedStatement;
//數據庫操作的基類
public class BaseDao {
Connection connection = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
//獲得數據庫資源
public boolean getConnection(){
try {
Class.forName("com.mysql.jdbc.Driver");
String url = "jdbc:mysql://localhost:9988/kgcnews?characterEncoding=utf8&useSSL=true";
connection = (Connection) DriverManager.getConnection(url,"root","123456");
} catch (ClassNotFoundException e) {
e.printStackTrace();
return false;
}catch (SQLException e) {
e.printStackTrace();
return false;
}
return true;
}
//增刪改
public int executeUpdate(String sql,Object[] params) {
int updateRows = 0;
if(this.getConnection()){
try {
pstmt = (PreparedStatement) connection.prepareStatement(sql);
//填充佔位符
for(int i=0;i<params.length;i++){
pstmt.setObject(i+1, params[i]);
}
updateRows = pstmt.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}
}
return updateRows;
}
//查詢
public ResultSet executeSQL(String sql,Object[] params) {
if(this.getConnection()){
try {
pstmt = (PreparedStatement) connection.prepareStatement(sql);
//填充佔位符
for(int i=0;i<params.length;i++){
pstmt.setObject(i+1, params[i]);
}
rs = pstmt.executeQuery();
} catch (SQLException e) {
e.printStackTrace();
}
}
return rs;
}
//釋放資源
public boolean closeResource(){
if(rs!=null){
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
return false;
}
}
if(pstmt!=null){
try {
pstmt.close();
} catch (SQLException e) {
e.printStackTrace();
return false;
}
}
if(connection!=null){
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
return false;
}
}
return true;
}
}
面向接口的 DAO 設計
- NewsDao.java 示例(放在dao包中):
import java.util.Date;
public interface NewsDao{
//增加新聞信息
public void addNews(int id,int categoryid,String title,String summary,String content,String author,Date createdate);
//刪除特定新聞標題
public void deleteNews(int id);
//修改特定新聞標題的方法
public void updateNews(int id,String title);
//查詢全部新聞信息
public void getNewsList(String title);
//查詢特定標題的新聞信息
public void getNewsByTitle(String title);
}
- NewsDaoImpl.java 示例(放在dao.impl包中):
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.Date
//用 JDBC 實現新聞數據 增 刪 改 操作
public class NewsDaoImpl extends BaseDao implements NewsDao{
//增加新聞信息
public void addNews(int id,int categoryid,String title,String summary,String content,String author,Date createdate){
try {
String sql = "INSERT INTO news_detail(id,categoryid,title,summary,content,author,createdate) VALUES(?,?,?,?,?,?,?)";
Object params[] = {id,categoryid,title,summary,content,author,createdate};
int i = this.executeUpdate(sql,params);
if(i > 0){
System.out.println("插入新聞成功!");
}
} finally {
this.closeResource();
}
}
//刪除特定新聞標題
public void deleteNews(int id){
try {
String sql = "DELETE FROM news_detail WHERE id=?";
Object params[] = {id};
int i = this.executeUpdate(sql,params);
if(i > 0){
System.out.println("刪除新聞成功!");
}
} finally {
this.closeResource();
}
}
//修改特定新聞標題的方法
public void updateNews(int id,String title){
try {
String sql = "UPDATE news_detail SET title=? WHERE id=?";
Object params[] = {id,title};
int i = this.executeUpdate(sql,params);
if(i > 0){
System.out.println("修改新聞成功!");
}
} finally {
this.closeResource();
}
}
//查詢全部新聞信息
public void getNewsList(String title){
try {
String sql = "select id,categoryid,title,summary,content,author,createdate from news_detail";
Object params[] = {};
ResultSet rs = this.executeSQL(sql, params);
while (rs.next()) {
int id = rs.getInt("id");
int categoryid = rs.getInt("categoryid");
String newsTitle = rs.getString("title");
String summary = rs.getString("summary");
String content = rs.getString("content");
String author = rs.getString("author");
Timestamp createdate = rs.getTimestamp("createdate");
System.out.println(id+"\t"+categoryid+"\t"+newsTitle+"\t"+summary+"\t"+content+"\t"+author+"\t"+createdate);
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
this.closeResource();
}
}
//查詢特定標題的新聞信息
public void getNewsByTitle(String title){
try {
String sql = "select * from news_detail where title=?";
Object params[] = {0};
ResultSet rs = this.executeSQL(sql, params);
while (rs.next()) {
int id = rs.getInt("id");
String newsTitle = rs.getString("title");
System.out.println(id+"\t"+newsTitle);
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
this.closeResource();
}
}
public static void main(String[] args) {
NewsDao dao = new NewsDaoImpl();
// dao.addNews(3, 1, "test", "test", "test", "Linyer", new Date());
// dao.deleteNews(3);
// dao.updateNews(3, "newTitle");
// dao.getNewsList("Java Web開課啦");
dao.getNewsByTitle("Java Web開課啦");
}
}
使用屬性文件管理數據
- 據庫發生改變時,需要重新修改代碼,重新編譯和部署。
- 將數據庫信息寫在配置文件中,讓程序通過讀取配置文件來獲取這些信息。
- 以
.properties
爲後綴的文件就是配置文件,存儲的信息爲鍵值對的形式。
- database.properties 示例(於 src 目錄下):
jdbc.driver=com.mysql.jdbc.driver
jdbc.connection.url=jdbc:mysql://localhost:9988/kgcnews?characterEncoding=utf8&useSSL=true
jdbc.connection.username=root
jdbc.connection.password=123456
- ConfigManager.java 示例(於 util 包中):
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
//讀取數據庫屬性文件,獲取數據庫連接信息
public class ConfigManager {
private Properties properties;
public ConfigManager(){
String configFile = "database.properties";
InputStream in = ConfigManager.class.getClassLoader().getResourceAsStream(configFile);
try {
properties.load(in);
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
//根據屬性文件中的鍵獲得對應的值
public String getString(String key){
return properties.getProperty(key);
}
}
單例模式
- 如何讓用戶只創建一個 ConfigManager
- 把構造方法私有。
- 程序提供給別人一個對象。
- 分兩種模式:懶漢模式 / 餓漢模式
- 區別在於 new 對象的時機不同。
- 懶漢模式
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
//讀取數據庫屬性文件,獲取數據庫連接信息
public class ConfigManager {
private static ConfigManager configManager;
private Properties properties;
private ConfigManager(){
String configFile = "database.properties";
InputStream in = ConfigManager.class.getClassLoader().getResourceAsStream(configFile);
try {
properties.load(in);
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
//提供給比兒一個唯一的ConfigManager對象
public static synchronized ConfigManager getInstance(){
if(configManager == null){
configManager = new ConfigManager();
}
return configManager;
}
//根據屬性文件中的鍵獲得對應的值
public String getString(String key){
return properties.getProperty(key);
}
}
- 餓漢模式
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
//讀取數據庫屬性文件,獲取數據庫連接信息
public class ConfigManager {
private static ConfigManager configManager = new ConfigManager();
private Properties properties;
private ConfigManager(){
String configFile = "database.properties";
InputStream in = ConfigManager.class.getClassLoader().getResourceAsStream(configFile);
try {
properties.load(in);
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
//提供給比兒一個唯一的ConfigManager對象
public static ConfigManager getInstance(){
return configManager;
}
//根據屬性文件中的鍵獲得對應的值
public String getString(String key){
return properties.getProperty(key);
}
}
數據源以及分層開發
理解和使用數據源
- 數據源
javax.sql.DataSource
接口負責建立與數據庫的連接- 由 Tomecat 提供,將連接保存在連接池中
1、數據源用來連接數據庫,獲得連接(Connection)對象
2、連接池用來管理連接(Connection)對象
3、在程序中使用 JNDI 獲取數據源
JNDI --> DataSource --> Connection --> 連接池
- 配置 tomcat 的 conf 中的 context.xml
<Resource name="jdbc/news"
auth="Container" type="javax.sql.DataSource" maxActive="100"
maxIdle="30" maxWait="10000" username="root" password="123456"
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://127.0.0.1:9988/kgcnews?characterEncoding=utf8&useSSL=true"/>
- 獲取數據庫連接
//獲取數據庫連接
public boolean getConnection2(){
try {
//初始化上下文
Context cxt = new InitialContext();
//獲取與邏輯名稱相關聯的數據源對象
DataSource ds = (DataSource) cxt.lookup("java:comp/env/jdbc/news");
//通過數據源獲取數據庫連接
connection = (Connection) ds.getConnection();
} catch (NamingException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
使用 JavaBean 封裝數據
- JavaBean
- 就是一個 Java 類
- 封裝業務邏輯
- 封裝數據
public void add(int id,int categoryld,String title,String summary,String content,Date createdate){
//方法體
}
public void add(新聞信息對象){
//方法體
}
如:
import java.sql.Date;
//新聞JavaBean,僅封裝數據(屬性、setter及getter)
public class News {
private int id;
private int categoryId;
private String title;
private String summary;
private String content;
private String picPath;
private String author;
private Date creatDate;
private Date modifyDate;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getCategoryId() {
return categoryId;
}
public void setCategoryId(int categoryId) {
this.categoryId = categoryId;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getSummary() {
return summary;
}
public void setSummary(String summary) {
this.summary = summary;
}
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public String getPicPath() {
return picPath;
}
public void setPicPath(String picPath) {
this.picPath = picPath;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public Date getCreatDate() {
return creatDate;
}
public void setCreatDate(Date creatDate) {
this.creatDate = creatDate;
}
public Date getModifyDate() {
return modifyDate;
}
public void setModifyDate(Date modifyDate) {
this.modifyDate = modifyDate;
}
}
分層開發思路
- dao 層 —> 數據訪問接口層
- 主要負責和數據操作相關的事情接口:NewsDao
- 接口實現類:NewsDaoImpl
- Service 層 —> 業務邏輯層主要負責與業務邏輯相關操作,對dao層的封裝和調用
- 接口:NewsService
- 接口實現類:NewsServiceImpl
JSP 標籤
- JSP 動作標籤
- 通過動作標籤,程序員可以在 JSP 頁面中把頁面的顯示功能部分封裝起來,使整個頁面更簡潔和易於維護
useBean
<jsp:useBean>
- 裝載一個將在 JSP 頁面中使用的 JavaBean,發揮 Java 組件重用的優勢
<jsp:useBean id="name" class="package.class" scope="scope">
註釋
- id–>JavaBean的引用名
- class–>JavaBean的類
- scope–>JavaBean的範圍
include
<jsp:include>
- 把指定文件插入正在生成的頁面中
<jsp:include page="URL">
- include 指令
<%@include file="URL"%>
<%@include%>
與<jsp:include>
區別:<jsp:include>
爲動態包含,將被包含頁面的結果包含進來。
先處理,再包含<%@include%>
爲靜態包含,將被包含頁面的內容包含進來。
先包含,再處理
頁面跳轉
<jsp:forward>
<jsp:forward page="URL">
Servlet 和 過濾器
Servlet 概述
- Servlet 做了什麼?
- 本身不做任何業務處理
- 只是接收請求並決定調用哪個 JavaBean 去處理請求
- 確定用哪個頁面來顯示處理返回的數據
- Servlet 是什麼?
- Server+Applet,是一種服務器端的 Java 應用程序
- 只有當一個服務器端的程序使用了 Servlet API 的時候,這個服務端的程序才能稱之爲 Servlet
- Servlet 特點
- Java 程序
- 運行在服務器端
- 需要 web 容器的支持
- 使用了 ServletAPI
- 本身不做任何業務處理,中間調度作用
Servlet API
javax.servlet.Servlet
接口- 所有Java Servlet的基礎接口類,規定了必須由Servlet具體類實現的方法集
javax.servlet.GenericServlet
類- 是 Servlet 的通用版本,是一種與協議無關的 Servlet
javax.servlet.http.HttpServlet
類 (使用較多)- 在 GenericServlet 基礎上擴展的基於 Http 協議的 Servlet
- init()
- service()
- doGet()
- doPost()
- destroy()
Servlet 中主要方法
- init(): servlet 的初始化方法,僅僅會執行一次
- service(): 處理請求和生成響應
- destroy(): 在服務器停止並且程序中的Servlet對象不再使用的時候調用,只執行一次
- ServletRequest
- 封裝客戶的請求信息
- 作用相當於 JSP 內置對象 request
- ServletResponse
- 創建響應信息,將處理結果返回給客戶端
- 作用相當於SP內置對象response
- ServletConfig: 包含了servlet的初始化參數信息
Servlet 生命週期
- Servlet 生命週期各個階段
- 加載和實例化
- 初始化
- 處理請求
- 銷燬
生命週期 | 誰來做 | 何時做 |
---|---|---|
實例化 | Servlet 容器 | 當 servlet 容器啓動或者容器檢測到客戶端請求時 |
初始化 | servlet 容器 | 實例化後,容器調用 Servlet 的 init() |
初始化 | 對象處理請求 | Servlet 容器得到客戶端請求並做出處理時 |
銷燬 | servlet 容器 | 當程序中的 Servlet 對象不再使用的時候,或者 Web 服務器停止運行的時候 |
跳轉路徑問題
-
HttpServletResponse 重定向 response.sendRedirect()
http://localhost:8080/news/servlet/AddServlet
- (1)相對路徑
response.sendRedirect("newsDetailList.jsp")
http://1ocalhost:8080/news/servlet/newsDetailList.jsp
- (2)絕對路徑
response.sendRedirect("/news/jsp/admin/newsDetailList.jsp")
http://1ocalhost:8080/news/jsp/admin/newsDetailList.jsp
- (1)相對路徑
-
HttpServletRequest 轉發 request.getRequestDispatcher().forward()
http://1ocalhost:8080/news/servlet/AddServlet
- (1)相對路徑
request.getRequestDispatcher("newsDetailList.jsp").forward()
http://localhost:8080/news/servlet/newsDetailList.jsp
- (2)絕對路徑
response.sendRedirect("/news/jsp/admin/newsDetailList.jsp")
http://localhost:8080/news/jsp/admin/newsDetailList.jsp
- (1)相對路徑
EL 與 JSTL
EL 表達式
EL 嚴格 區分 大小寫,初學者嚴格按規範書寫,有利於養成好的編碼習慣
- EL 表達式(Expression Language)
- 語法
${EL表達式}
例如:${username}
- 語法
EL 操作符
- 操作符
.
(用的比較多)- 獲取對象的屬性,例如:
${news.title}
- 獲取對象的屬性,例如:
- 操作符
[]
- 獲取對象的屬性,例如:
${news["title"]}
- 獲取集合中的對象,例如
newsList[0]
- 獲取對象的屬性,例如:
EL 功能
- 取得 JavaBean 對象的屬性
${news.title}
- 取得 數組、List、Map 類型對象的元素
${ist[0]}
- 使用各類運算符對原始數據進行簡單處理
${totalRecordCount/pageSizer}
- 屏蔽一些常見的異常
${username}
- 能實現簡單的自動類型轉換
${news}
相當於(News)request.getAttribute("news")
EL 訪問作用域
request.setAttribute("news",news);
- 兩種方式取數據:
- Java 小腳本:
request.getAttribute("news",news);
- 使用 EL 表達式:
${news}
或者${requestScope.news}
- Java 小腳本:
作用域 | Java代碼取值 | EL取值 |
---|---|---|
請求作用域 | request.getAttribute("news"); |
${requestscope.news} |
會話作用域 | session.getAttribute("username"); |
${sessionscope.username} |
程序作用域 | application.getAttribute("count"); |
${applicationscope.count} |
頁面作用域 | pageContext.getAttribute("userNum"); |
${pagescope.userNum} |
如果只有
${news}
會從作用域從小到大找
JSTL 表達式
- JSTL(JavaServerPages Standard Tag Library)
- JSP 標準標籤庫
- 實現 JSP 頁面中的邏輯控制
- JSTL 使用步驟
- 下載 jstl.jar 和 standard.jar 包
http://archive.apache.org/dist/jakarta/taglibs/standard/binaries/
(點擊以查看) - 將這兩個包複製到
WEB-INF\lib
目錄 - 在JSP頁面中添加指令
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%>
- 下載 jstl.jar 和 standard.jar 包
JSTL 標籤
標籤庫名稱 | 資源標示符(uri) |
---|---|
*<c:out/> |
輸出文本內容到out對象,常用於顯示特殊字符,顯示默認值 |
<c:set/> |
在作用域中設置變量或對象屬性的值 |
<c.remove/> |
在作用域中移除變量的值 |
*<c:if/> |
實現條件判斷結構 |
*<c:forEach/> |
實現循環結構 |
<c:url/> |
構造url地址 |
<c:param/> |
在url後附加參數 |
*<c:import/> |
在頁面中嵌入另一個資源內容 |
*<fmt:formatDate/> |
格式化時間 |
<fmt:formatNumber/> |
格式化數字 |
帶*
爲常用加標籤
分頁查詢
分頁查詢的後臺實現
- 用 SQL 語句查詢新聞總數
Select count(1)
From news_detail
- SQL語句限制顯示的行數
分頁查詢新聞數據,每頁顯示兩條數據,這裏顯示第 1 頁:
SELECT id,title,author,createdate
WHERE 1=1
FROM news detail
LIMIT 0,2
分頁查詢新聞數據,每頁顯示兩條數據,這裏顯示第 2 頁:
SELECT id,title,author,createdate
WHERE 1=1
FROM news detail
LIMIT 2,2
分頁查詢新聞數據,每頁顯示兩條數據,這裏顯示第 3 頁:
SELECT id,title,author,createdate
WHERE 1=1
FROM news detail
LIMIT 4,2
- 公用的分頁SQL:分頁後每頁顯示幾條新聞(頁面容量):pageSize
從第幾條數據開始顯示(當前頁碼pageNo-1)*pageSize
SELECT id,title,author,createdate
WHERE 1=1
FROM news detail
LIMIT (pageNo-1)*pageSize,pageSize
圓角邊框
border-radius: 20px 10px 50px 30px;