jsp詳細總結一(指令,Cookie,Session,response,分頁,上傳,下載)
一.開發專案前的配置
1.使用Eclipse開發Web專案(JSP專案) tomcat
2.在Eclipse中建立的Web專案:
瀏覽器可以直接訪問 WebContent中的檔案,
例如http://localhost:8888/MyJspProject/index1.jsp
其中的index1.jsp就在WebContent目錄中; 但是WEB-INF中的檔案
無法通過客戶端(瀏覽器)直接訪問,只能通過請求轉發來訪問
注意:並不是 任何的內部跳轉都能訪問WEB-INF;原因是 跳轉有2種方式:請求轉發 、重定向
3.配置tomcat執行時環境
jsp<->Servlet
b.右鍵專案->Build Path -> Add library ->Server Runtime
4.部署tomcat
在servers面板 新建一個 tomcat例項 , 再在該例項中 部署專案(右鍵-add)之後執行
注意:一般建議 將eclipse中的tomcat與 本地tomcat的配置資訊保持一致: 將eclipse中的tomcat設定為託管模式:【第一次】建立tomcat例項之後, 雙擊,選擇Server Location的第二項
5.統一字符集編碼
a.編碼分類:
設定jsp檔案的編碼(jsp檔案中的pageEncoding屬性): jsp -> java
一般將上述設定成 一致的編碼,推薦使用UTF-8
文字編碼:
i.將整個eclipse中的檔案 統一設定 (推薦)
ii.設定 某一個專案
iii.設定單獨檔案
二.jsp基礎知識
JSP的頁面元素: HTML java程式碼(指令碼Scriptlet)、指令、註釋
1.指令碼Scriptlet
i.
<%
區域性變數、java語句
%>
ii.
<%!
全域性變數、定義方法
%>
iii.
<%=輸出表達式 %>
一般而言,修改web.xml、配置檔案、java 需要重啟tomcat服務
2.指令
page指令
<%@ page …%>
page指定的屬性:
language:jsp頁面使用的指令碼語言
import:匯入類
pageEncoding:jsp檔案自身編碼 jsp ->java
contentType:瀏覽器解析jsp的編碼
<%@ page language=“java” contentType=“text/html; charset=UTF-8”
pageEncoding=“UTF-8” import=“java.util.Date” %>
3.註釋
html註釋 ,可以被客戶 通過瀏覽器檢視原始碼 所觀察到
java註釋// /…/
jsp註釋<%-- --%>
4.JSP九大內建物件(自帶的,不需要new也能使用物件)
out:輸出物件,向客戶端輸出內容
request:請求物件;儲存“客戶端向服務端傳送的請求資訊”
request物件的常見方法:
String getParameter(String name) :根據請求的欄位名key (input標籤的name屬性值) ,返回欄位值value (input標籤的value屬性值)
String[] getParameterValues(String name): 根據請求的欄位名key ,返回多個欄位值value (checkbox)
void setCharacterEncoding(“編碼格式utf-8”) :設定post方式的請求編碼 (tomcat7以前預設iso-8859-1,tomcat8以後改為了utf-8)
getRequestDispatcher(“b.jsp”).forward(request,response) ; :請求轉發 的方式跳轉頁面 A - > B
ServletContext getServerContext():獲取專案的ServletContext物件
4.統一請求的編碼 request
1.get方式請求 如果出現亂碼,解決:(請求亂碼)
a.統一每一個變數的 編碼 (不推薦)
new String( 舊編碼,新編碼);
name = new String(name.getBytes(“iso-8859-1”),“utf-8”);
修改server.xml ,一次性的 更改tomcat預設get提交方式的編碼 (utf-8)
建議 使用tomcat時, 首先在server.xml中 統一get方式的編碼… URIEncoding=“UTF-8”
tomcat7 (iso-8859-1)
tomcat8(utf-8)
2.post 方式請求 如果出現亂碼,解決:
request.setCharacterEncoding(“utf-8”) ;
5.response :響應物件
提供的方法:
void addCookie( Cookie cookie ); 服務端向客戶端增加cookie物件
void sendRedirect(String location ) throws IOException; :頁面跳轉的一種方式(重定向)
void setContetType(String type):設定服務端響應的編碼(設定服務端的contentType型別)
中文亂碼(響應亂碼)
response.setContentType(“text/html”; charset=“UTF-8”);
response.setCharacterEncoding(“utf-8”);
轉發、重定向:
轉發:
張三(客戶端) -> 【 服務視窗 A (服務端 ) -> 服務視窗B 】
重定向:
張三(客戶端) -> 服務視窗 A (服務端 ) ->去找B
張三(客戶端) -> 服務視窗 B (服務端 ) ->結束
6. session(服務端)
Cookie(客戶端,不是內建物件):Cookie是由 服務端生成的 ,再發送給客戶端儲存。
相當於 本地快取的作用: 客戶端(hello.mp4,zs/abc)->服務端(hello.mp4;zs/abc)
作用:提高訪問服務端的效率,但是安全性較差。
Cookie: name=value
javax.servlet.http.Cookie
public Cookie(String name,String value) //構造方法
String getName(): //獲取name
String getValue(): //獲取value
void setMaxAge(int expiry); //最大有效期 (秒)
服務端準備Cookie:
response.addCookie(Cookie cookie)
客戶端獲取cookie: request.getCookies();
a.服務端增加cookie :response物件;客戶端獲取物件:request物件
b.不能直接獲取某一個單獨物件,只能一次性將 全部的cookie拿到
通過F12可以發現 除了自己設定的Cookie物件外,還有一個name為 JSESSIONID的cookie
建議 cookie只儲存 英文數字,否則需要進行編碼、解碼
7.session會話:
客戶端第一次請求服務端時,(jsessionid-sessionid)服務端會產生一個session物件(用於儲存該客戶的資訊);
並且每個session物件 都會有一個唯一的 sessionId( 用於區分其他session);
服務端由會 產生一個cookie,並且 該cookie的name=JSESSIONID ,value=服務端sessionId的值;
然後 服務端會在 響應客戶端的同時 將該cookie傳送給客戶端,至此 客戶端就有了 一個cookie(JSESSIONID);
因此,客戶端的cookie就可以和服務端的session一一對應(JSESSIONID - sessionID)
客戶端第二/n次請求服務端時:服務端會先用客戶端cookie種的JSESSIONID 去服務端的session中匹配sessionid,如果匹配成功(cookie jsessionid和sesion sessionid),說明此使用者 不是第一次訪問,無需登入;
1.session方法:
String getId() :獲取sessionId
boolean isNew() :判斷是否是 新使用者(第一次訪問)
void invalidate():使session失效 (退出登入、登出)
void setAttribute()
Object getAttribute();
void setMaxInactiveInterval(秒) :設定最大有效 非活動時間
int getMaxInactiveInterval():獲取最大有效 非活動時間
cookie和session的區別:
三.分頁SQL
假設每頁顯示10條資料
1.mysql分頁:
mysql:從0開始計數
結論:
分頁:
第n頁的資料: 第(n-1)10+1條 – 第n10條
mysql的分頁語句:
limit 開始,多少條
select * from student limit 頁數*頁面大小,頁面大小
2.sqlserver/oracle:從1開始計數
第n頁 開始 結束
1 1 10
2 11 20
3 21 30
n (n-1)10+1 n10
select *from student where sno >=(n-1)10+1 and sno <=n10 ; --此種寫法的前提:必須是Id連續 ,否則 無法滿足每頁顯示10條資料
–1.如果根據sno排序則rownum會混亂(解決方案:分開使用->先只排序,再只查詢rownum) 2.rownum不能查詢>的資料
select s.* from student s order by sno asc;
select rownum, t.* from
(select s.* from student s order by sno asc) t
where rownum >=(n-1)10+1 and rownum <=n10 ;
3.oracle的分頁查詢語句:
select *from
(
select rownum r, t.* from
(select s.* from student s order by sno asc) t
)
where r>=(n-1)*10+1 and <=n*10 ;
優化:
select *from
(
select rownum r, t.* from
(select s.* from student s order by sno asc) t
where rownum<=n*10
)
where r>=(n-1)*10+1 ;
select *from
(
select rownum r, t.* from
(select s.* from student s order by sno asc) t
where rownum<=頁數*頁面大小
)
where r>=(頁數-1)*頁面大小+1 ;
4.QLServer分頁: 3種分頁sql
row_number() over(欄位) ;
sqlserver2003:top --此種分頁SQL存在弊端(如果id值不連續,則不能保證每頁資料量相等)
select top 頁面大小 * from student where id not in
( select top (頁數-1)*頁面大小 id from student order by sno asc )
2.sqlserver2005之後支援:
select *from
(
select row_number() over (sno order by sno asc) as r,* from student
where r<=n*10
)
where r>=(n-1)*10+1 ;
SQLServer此種分頁sql與oralce分頁sql的區別: 1.rownum ,row_number() 2.oracle需要排序(為了排序,單獨寫了一個子查詢),但是在sqlserver 中可以省略該排序的子查詢 因為sqlserver中可以通過over直接排序
3.sqlserver2012之後支援:
offset fetch next only
select * from student order by sno
offset (頁數-1)*頁面大小+1 rows fetch next 頁面大小 rows only ;
4.分頁實現
5個變數(屬性)
1.資料總數 100 103 (查資料庫,select count(*)…)
2.頁面大小 (每頁顯示的資料條數)20 (使用者自定義)
3.總頁數 (程式自動計算)
總頁數 = 100/20 =資料總數/頁面大小
總頁數 = 103/20 = 資料總數/頁面大小+1
—>
總頁數 = 資料總數%頁面大小==0? 資料總數/頁面大小:資料總數/頁面大小+1 ;
4.當前頁(頁碼) (使用者自定義)
5.當前頁的物件集合(實體類集合):每頁所顯示的所有資料 (10個人資訊)
List (查資料庫,分頁sql)
程式碼詳細
//Dao資料操作層
public List<Student> queryStudentsByPage(int currentPage, int pageSize) {
String sql = "select *from "
+"("
+"select rownum r, t.* from"
+"(select s.* from student s order by sno asc) t "
+"where rownum<=?"
+")"
+ "where r>=?"
;
Object[] params = {currentPage*pageSize,(currentPage-1)*pageSize+1};
List<Student> students = new ArrayList<>();
ResultSet rs = DBUtil.executeQuery(sql, params) ;
try {
while(rs.next()) {
Student student = new Student(rs.getInt("sno"),rs.getString("sname"),rs.getInt("sage"),rs.getString("saddress")) ;
students.add(student) ;
}
} catch (SQLException e) {
e.printStackTrace();
}catch (Exception e) {
e.printStackTrace();
}
return students;
}
//Servlet顯示層後臺
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
IStudentService studentService = new StudentServiceImpl();
int count = studentService.getTotalCount() ;//資料總數
//將分頁所需的5個欄位(其中有1個自動計算,因此實際只需要組裝4個即可),組裝到page物件之中
Page page = new Page();
String cPage = request.getParameter("currentPage") ;//
if(cPage == null) {
cPage = "1" ;
}
int currentPage = Integer.parseInt( cPage );
page.setCurrentPage(currentPage);
// int currentPage = 2;//頁碼
//注意 順序
int totalCount = studentService.getTotalCount() ;//總資料數
page.setTotalCount(totalCount);
/* currentPage:當前頁(頁碼)
students :當前頁的資料集合(當前頁的所有學生)
*/
int pageSize = 3;
page.setPageSize(pageSize);
List<Student> students = studentService.queryStudentsByPage(currentPage, pageSize) ;
System.out.println(students);
System.out.println(count);
page.setStudents(students);
request.setAttribute("p", page);
request.getRequestDispatcher("index.jsp").forward(request, response);
}
//jsp頁面
<table border="1px">
<tr>
<th>學號</th>
<th>姓名</th>
<th>年齡</th>
<th>操作</th>
</tr>
<%
//獲取request域中的資料
Page p = (Page)request.getAttribute("p") ;
for(Student student:p.getStudents()){
%>
<tr>
<td><a href="QueryStudentBySnoServlet?sno=<%=student.getSno() %>"><%=student.getSno() %></a> </td>
<td><%=student.getSname() %></td>
<td><%=student.getSage() %></td>
<td> <a href="DeleteStudentServlet?sno=<%=student.getSno() %> ">刪除</a> </td>
</tr>
<%
}
%>
</table>
<a href="add.jsp">新增</a><br/>
<%
if(p.getCurrentPage() ==p.getTotalPage()){ //尾頁
%> <a href="QueryStudentByPage?currentPage=1">首頁</a>
<a href="QueryStudentByPage?currentPage=<%=p.getCurrentPage()-1%> ">上一頁</a>
<%
}
else if(p.getCurrentPage() ==1){//首頁
%> <a href="QueryStudentByPage?currentPage=<%=p.getCurrentPage()+1%> ">下一頁</a>
<a href="QueryStudentByPage?currentPage=<%=p.getTotalPage()%>">尾頁</a>
<%
}
else{//中間
%>
<a href="QueryStudentByPage?currentPage=1">首頁</a>
<a href="QueryStudentByPage?currentPage=<%=p.getCurrentPage()-1%> ">上一頁</a>
<a href="QueryStudentByPage?currentPage=<%=p.getCurrentPage()+1%> ">下一頁</a>
<a href="QueryStudentByPage?currentPage=<%=p.getTotalPage()%>">尾頁</a>
<%
}
5.上傳和下載
1.引入2個jar
apache: commons-fileupload.jar元件
commons-fileupload.jar依賴 commons-io.jar
2.程式碼:
前臺jsp:
表單提交方式必須為post
在表單中必須增加一個屬性 entype=“multipart/form-data”
3.下載:不需要依賴任何jar
a.請求(地址a form),請求Servlet
b.Servlet通過檔案的地址 將檔案轉為輸入流 讀到Servlet中
c.通過輸出流 將 剛才已經轉為輸入流的檔案 輸出給使用者
注意:下載檔案 需要設定2個 響應頭:
response.addHeader(“content-Type”,“application/octet-stream” );//MIME型別:二進位制檔案(任意檔案)
response.addHeader(“content-Disposition”,“attachement;filename=”+fileName );//fileName包含了檔案字尾:
實現程式碼:
//前端頁面
<form action="UploadServet" method="post" enctype="multipart/form-data">
學號:<input name="sno" /><br/>
姓名:<input name="sname" /><br/>
上傳照片: <input type="file" name="spicture"/>
<br/>
<input type="submit" value="註冊"/>
</form>
<a href="DownloadServlet?filename=MIME.png">MIME</a>
後臺程式碼
//Servlet上傳照片程式碼
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
response.setCharacterEncoding("utf-8");
response.setContentType("text/html; charset=UTF-8");
// 上傳
// request.getParameter("sname")
try {
boolean isMultipart = ServletFileUpload.isMultipartContent(request);
if (isMultipart) {// 判斷前臺的form是否有 mutipart屬性
// FileItemFactory factory = new DiskFileItemFactory();
DiskFileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);
//設定上傳檔案時 用到的臨時檔案的大小DiskFileItemFactory
factory.setSizeThreshold(10240);//設定臨時的緩衝檔案大小為10
factory.setRepository(new File("D:\\study\\uploadtemp"));//設定臨時檔案的目錄
//控制上傳單個檔案的大小 20KB ServletFileUpload
upload.setSizeMax(20480);//位元組B
Thread.sleep(3000);
// 通過parseRequest解析form中的所有請求欄位,並儲存到 items集合中(即前臺傳遞的sno sname
// spicture此時就儲存在了items中)
List<FileItem> items = upload.parseRequest(request);
// 遍歷items中的資料(item=sno sname spicture)
Iterator<FileItem> iter = items.iterator();
while (iter.hasNext()) {
FileItem item = iter.next();
String itemName = item.getFieldName();
int sno = -1;
String sname = null;
// 判斷前臺欄位 是普通form表單欄位(sno sname),還是檔案欄位
// request.getParameter() -- iter.getString()
// 判斷是否是普通表單欄位
if (item.isFormField()) {
if (itemName.equals("sno")) {// 根據name屬性 判斷item是sno sname 還是spicture?
sno = Integer.parseInt(item.getString("UTF-8"));
} else if (itemName.equals("sname")) {
sname = item.getString("UTF-8");
} else {
System.out.println("其他欄位xxx.....");
}
} else {// spicture 123
// 檔案 上傳
// 檔名 getFieldName是獲取 普通表單欄位的Name值
// getName()是獲取 檔名
String fileName = item.getName();//a.txt a.docx a.png
String ext = fileName.substring( fileName.indexOf(".")+1 ) ;
if(!(ext.equals("png") || ext.equals("gif") ||ext.equals("jpg"))) {
System.out.println("圖片型別有誤!格式只能是 png gif jpg");
return ;//終止
}
// 獲取檔案內容 並上傳
// 定義檔案路徑:指定上傳的位置(伺服器路徑)
// 獲取伺服器路徑D:\\study\\apache-tomcat-8.5.30\\wtpwebapps\\UpAndDown\\upload
// String path =request.getSession().getServletContext().getRealPath("upload") ;
String path = "D:\\study\\upload";
File file = new File(path, fileName);
item.write(file);// 上傳
System.out.println(fileName + "上傳成功!");
return;
}
}
}
}
catch (FileUploadBase.SizeLimitExceededException e) {//SizeLimitExceededException是FileUploadException的一個子類
System.out.println("上傳檔案大小超過限制!最大20KB");
}
catch (FileUploadException e)
{
e.printStackTrace();
}
// 解析請求
catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//Servlet 下載程式碼
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
//獲取需要下載的檔名
String fileName = request.getParameter("filename") ;//form 、a href、 ...Server?a=b
//下載檔案:需要設定 訊息頭
response.addHeader("content-Type","application/octet-stream" );//MIME型別:二進位制檔案(任意檔案)
response.addHeader("content-Disposition","attachement;filename="+fileName );//fileName包含了檔案字尾:abc.txt
//Servlet通過檔案的地址 將檔案轉為輸入流 讀到Servlet中
InputStream in = getServletContext().getResourceAsStream("/res/MIME.png") ;
//通過輸出流 將 剛才已經轉為輸入流的檔案 輸出給使用者
ServletOutputStream out = response.getOutputStream() ;
byte[] bs = new byte[10];
int len=-1 ;
while( (len=in.read(bs)) != -1) {
out.write(bs,0,len);
}
out.close();
in.close();
}