JavaWeb-Servlet
簡(jiǎn)介

動(dòng)態(tài)web技術(shù)servlet是sun公司開(kāi)發(fā)動(dòng)態(tài)web的一門(mén)技術(shù)
編寫(xiě)一個(gè)類,實(shí)現(xiàn)servlet,將開(kāi)發(fā)好的java類部署到web服務(wù)器中
servlet程序需要類實(shí)現(xiàn)接口----部署到服務(wù)器
HttpServlet實(shí)現(xiàn)了Servlet接口
把實(shí)現(xiàn)了Servlet接口的java程序叫做Servlet
Servlet的生命周期,Servlet在用戶第一次請(qǐng)求時(shí)才創(chuàng)建,直到服務(wù)器關(guān)閉才銷(xiāo)毀。
HelloServlet
構(gòu)建一個(gè)普通的Maven項(xiàng)目,刪掉src目錄,創(chuàng)建moudel文件
關(guān)于Maven父子工程:父項(xiàng)目中有modules,子項(xiàng)目中有parent,父項(xiàng)目的jar包,子項(xiàng)目可以直接享用。
Maven環(huán)境優(yōu)化:修改web.xml為最新的,tomcat/webapps/root/web-inf/web.xml,將maven 的結(jié)構(gòu)搭建完整
編寫(xiě)步驟:
編寫(xiě)一個(gè)普通類
實(shí)現(xiàn)Servlet接口,直接繼承HttpServlet,父類的包可以直接繼承。
實(shí)現(xiàn)Servlet
如果沒(méi)有,解決辦法:手動(dòng)寫(xiě)入parent,help->更新idea,File->關(guān)閉項(xiàng)目再打開(kāi)。沒(méi)有parent的原因: 去父工程的依賴中刪除scope標(biāo)簽,重建創(chuàng)建子模塊即可
services 方法里面做的事情是調(diào)用doGet或者doPost方法,請(qǐng)求實(shí)現(xiàn)的不同的方式,可以相互調(diào)用,業(yè)務(wù)邏輯相同。
編寫(xiě)Servlet的映射
映射:Java程序需要瀏覽器訪問(wèn),瀏覽器需要連接web服務(wù)器,所以需要在web服務(wù)中注冊(cè)servlet,還需要給一個(gè)瀏覽器可以訪問(wèn)的路徑。
容器通過(guò)配置文件web.xml找相應(yīng)的servlet這樣有助于靈活和可維護(hù)性。
置web.xml是讓容器知道所發(fā)送過(guò)來(lái)的請(qǐng)求是由哪個(gè)servlet處理,然后把httprequest和httpresponse對(duì)象注入到該servlet中。
在web.xml中配置servlet(自己寫(xiě)的servlet實(shí)現(xiàn)類位置)和servlet-mapping(請(qǐng)求路徑)
[之后通過(guò)注解@WebServlet("/路徑")就直接解決]
配置Tomcat
Servlet原理
mapping
一個(gè)Servlet可以指定通用映射路徑
1
2
3
4
可以自定義后綴實(shí)現(xiàn)請(qǐng)求映射,注意.*前面不能加映射
1
默認(rèn)請(qǐng)求路徑
1
設(shè)置錯(cuò)誤頁(yè)面
doGet{resp.setContentType("text/html;charset=utf-8");}// 網(wǎng)絡(luò)文件的類型和網(wǎng)頁(yè)的編碼,決定文件接收方將以什么形式、什么編碼讀取這個(gè)文件,
1
1
2
3
4
5
6
7
8
優(yōu)先級(jí):指定了固有的映射路徑優(yōu)先級(jí)最高,如果找不到則走默認(rèn)處理請(qǐng)求。
HttpServlet的實(shí)現(xiàn)類
this.getInitParameter //初始化參數(shù) this.getServletConfig //Servlet配置 this.getServletContext //Servlet上下文
1
2
3
ServletContext
4/20
web容器(Tomcat)在啟動(dòng)時(shí),會(huì)為每一個(gè)web程序創(chuàng)建一個(gè)對(duì)應(yīng)的ServletContext對(duì)象,代表當(dāng)前的web應(yīng)用。
共享數(shù)據(jù):servletContext:整個(gè)應(yīng)用范圍:服務(wù)器范圍,只要服務(wù)器不關(guān)閉,數(shù)據(jù)一致存在。ServletContext對(duì)象相當(dāng)于dao是Servlet容器的總司令部。ServletContext對(duì)象有且只有一個(gè)該對(duì)象,這個(gè)其實(shí)就是單例模式;
public class SetServlet extends HttpServlet{ ServletContext context = this.getServletContext(); //保存數(shù)據(jù),get和set String name = "xx"; context.setAttribute("username", name); //將一個(gè)數(shù)據(jù)保持在ServletContext中,名字為username,值為name }
1
2
3
4
5
public class GetServlet extends HttpServlet{ @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{ ServletContext context = this.getServletContext(); //保存數(shù)據(jù),get和set String name = (String)context.getAttribute("username", name); //獲取前面存儲(chǔ)的數(shù)據(jù) resp.setContentType("text/html;charset=utf-8");// 一次寫(xiě)兩個(gè)參數(shù)的方法 resp.getWriter().print("name"+name); //req是請(qǐng)求 resp是響應(yīng) } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{ doGet(rep, resp);} }
1
2
3
4
5
6
7
8
9
10
11
12
13
1
2
3
4
5
6
ServletContext context = this.getServletContext(); String url = context.getInitParameter("url"); //獲取web.xml里面的context-param,初始化參數(shù) resp.getWriter().print(url);
1
2
3
//路徑轉(zhuǎn)發(fā),路徑不會(huì)變,這是springmvc dispatchServlet的實(shí)現(xiàn)原理 ServletContext context = this.getServletContext(); // RequestDispatcher requestDispatcher = context.getRequestDispatcher("/gp");//轉(zhuǎn)發(fā)請(qǐng)求路徑,/代表當(dāng)前web應(yīng)用 // requestDispatcher.forward(req, resp);//調(diào)用forward實(shí)現(xiàn)請(qǐng)求轉(zhuǎn)發(fā); context.getRequestDispatcher("/gp").forward(req, resp);
1
2
3
4
getRequestDispatcher分成兩種,可以用request調(diào)用,也可以用getServletContext()調(diào)用 不同的是而this.getServletContext().getRequestDispatcher(url)的url只能是絕對(duì)路徑。
重定向與請(qǐng)求轉(zhuǎn)發(fā)的區(qū)別
轉(zhuǎn)發(fā)是服務(wù)器內(nèi)部完成的 重點(diǎn)向是服務(wù)器返回新路徑再由瀏覽器請(qǐng)求
轉(zhuǎn)發(fā)路徑不變,重定向路徑改變,重定向兩次請(qǐng)求,轉(zhuǎn)發(fā)一次請(qǐng)求,注意重定向時(shí)A(客戶端)是發(fā)送了兩次請(qǐng)求,請(qǐng)求轉(zhuǎn)發(fā)時(shí)A只發(fā)送了一次請(qǐng)求,而服務(wù)器端對(duì)該請(qǐng)求進(jìn)行了轉(zhuǎn)發(fā)
properties讀取屬性值
Properties及其重要的一個(gè)集合,是唯一個(gè)可以與文件交互的集合,也是springboot的靈魂
類路徑classpath:在web應(yīng)用的target文件下的WEB-INF文件下的class和lib,classpath只能表示lib目錄和WEB-inf/classes路徑下的文件
在java和resources目錄下建立properties(特性),都被打包到了同一個(gè)文件下:class,這個(gè)路徑稱為classpath。
在resources目錄下建立db.properties。target下面沒(méi)有db.properties的再pom里添加在build中配置resources后,再重啟一下IDEA就好了了
獲取:文件流
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{ InputStream in = this.getServletContext().getResourceAsStream("/WEB-INF/classes/db.properties"); //在web應(yīng)用里獲取db.properties, /代表當(dāng)前web項(xiàng)目 Properties prop = new Properties(); prop.load(in); String user = prop.getPropery("username"); resp.setHeader("content-type","text/html;charset=UTF-8"); resp.getWriter().print(user); }
1
2
3
4
5
6
7
8
Response
web服務(wù)器接收到客戶端的http請(qǐng)求,針對(duì)這個(gè)請(qǐng)求,分別創(chuàng)建一個(gè)代表請(qǐng)求的HttpServletRequest對(duì)象,代表響應(yīng)的HttpServletResponse;
1.加載和實(shí)例化2.初始化3.請(qǐng)求處理4.服務(wù)終止 沒(méi)講彈幕補(bǔ)充下就可以了
向?yàn)g覽器發(fā)送數(shù)據(jù)方法
ServletOutputStream getOutputStream() throws IoException; // 寫(xiě)平常流 PrintWriter getWriter() throwsIoException; // 寫(xiě)中文
1
2
負(fù)責(zé)向?yàn)g覽器發(fā)送響應(yīng)頭的方法:
setCharacterEncoding(String var1);
響應(yīng)的狀態(tài)碼。
1.向?yàn)g覽器輸出消息
2.下載文件:文件路徑,文件名,瀏覽器支持,獲取下載文件的輸入流,創(chuàng)建緩沖區(qū),獲取OutputStream對(duì)象,將FileOutputStream流寫(xiě)入到Buffer緩存區(qū)中,使用OutputStream將緩沖區(qū)的數(shù)據(jù)輸出到客戶端。
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{ // 獲取下載文件路徑 String realPath = this.getServletContext().getRealPath("/xxx"); // 獲取文件名 String filename = realPath.subString(realPath.lastIndexOf("\") + 1); //獲取最后一個(gè)//后面的字符串 // 獲取瀏覽器支持(Content-Disposition),web下載文件的頭消息 resp.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(filename,"UTF-8")); //URLEncoder中文字符編碼轉(zhuǎn)換 // 獲取下載文件的輸入流 FileOutputStream fileOutputStream= new FileOutputStream(realPath); // 創(chuàng)建緩沖區(qū) int len = 0; byte[] buffer = new byte[1024]; // 獲取OutputStream對(duì)象 ServletOutputStream outputStream = resp.getOutputStream(); // 將FileOutputStream流寫(xiě)入到Buffer緩存區(qū)中 while(len = in.read(buffer) != -1){ outputStream.write(buffer, 0, len); } // in.close() ou.close(); }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
驗(yàn)證碼:
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{ // 瀏覽器3秒自動(dòng)刷新一次 resp.setHeader("refresh", "3"); // 在內(nèi)存中創(chuàng)建圖片 BufferedImage bufferedImage = new BufferedImage(80, 20, BufferedImage.TYPE_INT_BGR); // 得到圖片,用畫(huà)筆進(jìn)行畫(huà)圖 Graphics2D graphics= (Graphics2D)image.getGraphics(); // 筆 // 設(shè)置圖片背景顏色 graphics.setColor(Color.white); g.fillRect(0, 0, 80, 20); //寫(xiě)入數(shù)據(jù) g.setColor(Color.BLUE); g.setFont(new Font(null, Font, BOLF, 20)); g.drawString(makeNUm(), 0 ,20); // 請(qǐng)求用圖片的方式打開(kāi) resp.setConentType(:"image.jpeg"); // 緩存策略,網(wǎng)站緩存,瀏覽器不緩存, 響應(yīng)頭設(shè)置 resp.setDateHeader("expires", -1); resp.setHeader("Cahce-Control", "no-cache");// 不緩存 resp.setHeader("Pragma","no-cahce"); // 把圖片寫(xiě)給瀏覽器 boolean write = ImageIO.wirte(image, "jpg", resp.getOutputStream()); } private String makeNum(){ Random random - new Random(); String num = random.nextInt(9999999) + ""; StringBuffer s = new StringBuffer(); // 生成七位數(shù) for (int i = 0; i < 7- num.length(); i++){ s.append("0"); } num = s.toSring() + num; return num; }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
一個(gè)web資源,收到客戶端請(qǐng)求后,通知客戶端去訪問(wèn)另一個(gè)web資源。
resp.sendRedirect("/r/img"); // 重定向,/r是項(xiàng)目的虛擬目錄,/r是配Tomcat的時(shí)候設(shè)置的
1
sendRedirect是封裝后的setHeader和setStatus ,原理:
resp.setHeader("Loaction", "/r/img"); //轉(zhuǎn)發(fā)地址 resp.setStatus(302); // 重定向標(biāo)志
1
2
重定向和轉(zhuǎn)發(fā)的區(qū)別:
相同點(diǎn):頁(yè)面都會(huì)跳轉(zhuǎn)
不同點(diǎn):重定向url變化(302),轉(zhuǎn)發(fā)url不變化(307),轉(zhuǎn)發(fā)時(shí)"/“代表的是本應(yīng)用程序的根目錄 重定向時(shí)”/"代表的是webapps目錄,轉(zhuǎn)發(fā)是服務(wù)器內(nèi)部的,不需要寫(xiě)項(xiàng)目路徑。
登錄跳轉(zhuǎn):
注解:在類名上加個(gè)@WebServlet("/地址")就行
servlet:
webapp/index.jsp(首頁(yè)):
1
2
3
4
5
6
7
webapp/WEB_INF/web.xml
1
2
3
4
5
6
7
8
9
RequestServlet.java
public class RequestServlet extends HttpServlet{ @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{ resp.setCharacterEncoding("utf-8"); // 后臺(tái)發(fā)送中文亂碼 // 處理請(qǐng)求 String name = req.getParameter("username"); String password = req.getParameter("password"); System.out.println(name + "+" + password); // 重定向,注意路徑問(wèn)題,跳轉(zhuǎn) resp.sendRedirect("/r/success.jsp"); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException{ doGet(rep, resp);} }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
Request
HttpServletRequest代表客戶端請(qǐng)求,用戶通過(guò)Http協(xié)議訪問(wèn)服務(wù)器,HTTP請(qǐng)求的消息會(huì)被封裝到HttpServletRequest,通過(guò)這個(gè)HttpServletRequest的方法,獲取客戶端的信息。
req.setCharacterEncoding("utf-8"); // 后臺(tái)接收中文亂碼 req.getParameter; //獲取前端傳遞參數(shù) String[] h = req.getParameterValues(:"h); //獲取前端傳遞數(shù)組參數(shù)(checkbox)
1
2
3