1. 程式人生 > 其它 >jsp詳細總結一(指令,Cookie,Session,response,分頁,上傳,下載)

jsp詳細總結一(指令,Cookie,Session,response,分頁,上傳,下載)

技術標籤:javajsp

一.開發專案前的配置

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

a.將tomcat/lib中的servlet-api.jar加入專案的構建路徑
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

設定瀏覽器讀取jsp檔案的編碼(jsp檔案中content屬性)
一般將上述設定成 一致的編碼,推薦使用UTF-8
文字編碼:
i.將整個eclipse中的檔案 統一設定 (推薦)
ii.設定 某一個專案
iii.設定單獨檔案

二.jsp基礎知識

JSP的頁面元素: HTML java程式碼(指令碼Scriptlet)、指令、註釋
1.指令碼Scriptlet

i.    
	<%
			區域性變數、java語句
	%>
ii.
	<%!
			全域性變數、定義方法
	%>
iii.
	 <%=輸出表達式 %>

一般而言,修改web.xml、配置檔案、java 需要重啟tomcat服務

但是如果修改 Jsp\html\css\js ,不需要重啟
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();
		
	}