一、Listener監(jiān)聽器
1、JavaWeb三大組件之一(Servlet程序、Fiflter過濾器、Listener監(jiān)聽器)
2、Listener是JavaEE的規(guī)范,也就是接口
3、監(jiān)聽器的作用是:監(jiān)聽某事物的變化,回調(diào)函數(shù)反饋處理
二、 ServletContextListener 監(jiān)聽器
1、ServletContextListener 可以監(jiān)聽ServletContext對象的創(chuàng)建和銷毀
2、ServletContext 對象在web工程啟動的時候創(chuàng)建,在web工程停止的時候銷毀
3、監(jiān)聽到web工程的創(chuàng)建和銷毀后都會分別調(diào)用ServletContextListener的回調(diào)方法
三、使用方式
1、創(chuàng)建一個類實現(xiàn)ServletContextListener接口
2、實現(xiàn)兩個方法
3、在web.xml中配置監(jiān)聽器。 如:
<listener>
<listener-class>com.demo.listener.MyServletContextListenerImpl</listener-class>
</listener>
==============================================================================================
一、EL 表達式
Expression Language,表達式語言
作用:代替jsp頁面中的表達式腳本在jsp頁面中進行數(shù)據(jù)的輸出。(更簡潔)
例:
表達式腳本輸出key值:<%=request.getAttribute("key")%><br/>
EL表達式輸出key值:${key}
注:表達式腳本輸出null; EL表達式輸出""空串
二、EL表達式搜索四個域的順序
按從小到大的順序從域中搜索
1、pageContext.setAttribute("key", "pageContext");
2、request.setAttribute("key", "request");
3、session.setAttribute("key", "session");
4、application.setAttribute("key", "application");
三、EL表達式輸出bean、集合、數(shù)組屬性等
${personBeanKey}
${personBeanKey.arrayDatas[1]}
${personBeanKey.listDatas[1]}
${personBeanKey.mapDatas.key1}
注:EL表達式 其實是找尋bean中的get方法去執(zhí)行的。
四、EL運算
1、關(guān)系運算
==和eq是一樣的;!=和ne是一樣的;
<和lt;>和gt;<=和le;>=和ge;
例:if(12==12){};? if(12 eq 12){}
2、邏輯運算
&&和and是一樣的;||和or是一樣的;!和not是一樣。
3、算數(shù)運算
+-*/
/和div是一樣的;%和mod是一樣的
4、empty運算
判斷數(shù)據(jù)是否為空,空輸出true,否則false
例: ${empty dataStr}
注:數(shù)組對象等判空時,元素個數(shù)為零則為空,返回true
5、三元運算
表達式?“true”:“false”
6、“.”點運算和[]中括號運算
例:${personBeanKey.arrayDatas[1]}
中括號處理特殊字符key,如:
key值為a.a.a時,錯誤輸出:${map.a.a.a};正確輸出:${map['a.a.a']}
key值為b+b+b時,錯誤輸出:${map.b+b+b};正確輸出:${map['b+b+b']}
五、EL表達式的11個隱含對象
是EL表達式中自己定義的,可以直接使用。
PageContextImpl pageContext; // 獲取jsp中九大內(nèi)置對象
Map<String, Obejct> pageScope;// 獲取PageContext域中的數(shù)據(jù)
Map<String, Obejct> requestScope;// 獲取Request域中的數(shù)據(jù)
Map<String, Obejct> sessionScope;// 獲取Session域中的數(shù)據(jù)
Map<String, Obejct> applicationScope;// 獲取ServletContext域中的數(shù)據(jù)
Map<String, String> param;// 獲取請求參數(shù)的值
Map<String, String[]> paramValues;// 獲取請求參數(shù)的值,獲取多個值的時候使用
Map<String, String> header;// 獲取請求頭的信息
Map<String, String[]> headerValues;// 獲取請求頭的信息,獲取多個值的時候使用
Map<String, Cookie> cookie;// 獲取當前請求的Cookie信息
Map<String, String> initParam;// 獲取web.xml中配置的<context-param>上下文參數(shù)
注:
1、pageContext獲取到九大內(nèi)置對象可以得到的信息有:
scheme協(xié)議、serverName請求服務(wù)器ip、serverPort請求服務(wù)器端口、
contextPath工程路徑、method請求方法、remoteHost客戶端ip地址、session.id會話的id編號
例:
方式一:${pageContext.request.scheme} 獲取協(xié)議
方式二:
<% pageContext.setAttribute("req", request); %>
${req.scheme}
2、之前說了可以直接${key1};輸出數(shù)據(jù)。但四個域中都有同一個key值時,可以通過上面的對象點key值輸出數(shù)據(jù)。四個域中都有同一個key值時,可以通過上面的對象點key值輸出數(shù)據(jù)。
如:pageScope.key1
3、獲取Cookie的名稱:${cookie.JSESSIONID.name}
獲取Cookie的值:${cookie.JSESSIONID.value}
六、JSTL標簽庫
JSP標準標簽庫
EL表達式主要是為了替換jsp中的表達式腳本,而標簽庫則是為了替換代碼腳本,使得jsp頁面更加簡潔
<c:set />標簽 例:<c:set scope="page" var="key1" value="value1"/> 注:scope 屬性表示設(shè)置保存到哪個域,page指pageContext
<c:if />標簽 例:<c:if test="${12==12}"/> 注:test屬性表示判斷的條件(使用EL表達式輸出)
<c:choose>、<c:when>、<c:otherwise>標簽 多路判斷,類似switch...case...default
例:
<% request.setAttribute("height", 199); %>
<c:choose>
<c:when test="${requestScope.height > 190}">
<h1>大于190</h1>
</c:when>
<c:when test="${requestScope.height > 180}">
<h1>大于180</h1>
</c:when>
<c:otherwise>
<h1>剩下的情況</h1>
</c:otherwise>
</c:choose>
注:
1、choose表示開始選擇判斷, when表示
2、不用像case一樣break;
3、標簽里不能使用html注釋<!-- -->,要使用jsp注釋;<%-- --%>
4、when標簽的父標簽一定要是choose標簽。(標簽嵌套時會用到)
<c:forEach />標簽
例:遍歷1到10(begin 開始遍歷的索引值;end結(jié)束的索引值;step 遍歷的步長值,類似于i+=2)
<c:forEach begin="1" end="10" step="2"var="i">
${i} <br>
</c:forEach>
遍歷數(shù)組(items數(shù)組集合,var輸出對象; varStatus對象獲取到遍歷的數(shù)據(jù)、索引、個數(shù)、是否第一、是否最后、步長等)
<c:forEach items="${requestScope.listDatas}" var="item" varStatus="status">
${item} <br>
</c:forEach>
遍歷Map(itemsMap集合,item表示每一組鍵值對,取鍵item.key,取值item.value)
<c:forEach items="${requestScope.map}" var="item">
${item} <br>
</c:forEach>
注:
1、先導(dǎo)入jstl標簽庫的jar包
2、使用taglib指令在代碼引入<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
七、文件的上傳
1、要有一個form標簽,method=post請求
2、form標簽的encType屬性值必須為multipart/form-data值; 表示提交的數(shù)據(jù)以多段的形式進行拼接,再以二進制形式提交到服務(wù)器
3、在form標簽中使用input type=file添加上傳的文件
4、編寫服務(wù)器代碼接收處理上傳的數(shù)據(jù)
注:
1、數(shù)據(jù)中的boundary 表示每段數(shù)據(jù)的分隔符,
2、瀏覽器會隨機生成一段字符作為每段數(shù)據(jù)的分界符。(比如:------WebKitFormBoundary9d39iEShBIMraATK)
3、分界符后面加-- 就表示結(jié)束了。
4、文件解析框架:
commons-fileupload-1.2.1.jar
commons-io-1.4.jar
jar包中的類:ServletFileupload 用于解析上傳的數(shù)據(jù)
isMultipart() 是否多段
parseRequest() 解析上傳的數(shù)據(jù)
isFormField() 判斷當前這個表單項是否是普通的表單項還是上傳的文件類型
true表示普通類型表單項;false表示上傳的文件類型
getFieldName() 獲取表單項的name屬性值
getString() 獲取當前表單項的值
getName() 獲取上傳的文件名
write(file) 將上傳的文件寫到參數(shù)file所指向的硬盤位置
七、文件的下載
1、獲取要下載的文件名
2、讀取要下載的文件內(nèi)容
3、把下載的文件內(nèi)容回傳給客戶端
4、在回傳前,通過響應(yīng)頭告訴客戶端返回的數(shù)據(jù)類型
5、通過響應(yīng)頭告訴客戶端收到的數(shù)據(jù)是用于下載使用
八、會話跟蹤方案
1、方案一:Cookie技術(shù)
Cookie保存于瀏覽器
優(yōu)點:HTTP協(xié)議中支持的技術(shù),直接用。
缺點:移動端APP無法使用Cookie;不安全,用戶可以自己禁用Cookie; 不能跨域(跨域指的是,前后端分別部署到不同的ip服務(wù)器。)
例:服務(wù)器代碼設(shè)置
設(shè)置Cookie:response.addCookie(new Cookie(COOKIE_KEY, "hahaha"));
獲取Cookie:request.getCookies().getName();cookie.getValue());
2、方案二:Session
Session保存于服務(wù)器,服務(wù)器會話對象Session中保存key、value發(fā)給瀏覽器
優(yōu)點:存在服務(wù)器中,安全的很。
缺點:多個服務(wù)器時無法使用(集群)、Cookie的缺點
Session設(shè)置值:session.setAttribute(SESSION_KEY, "heiheihei");
Session獲取值:request.getSession().getAttribute(SESSION_KEY);
3、方案三:令牌技術(shù)
一段字符串
優(yōu)點:支持PC端、移動端;解決集群環(huán)境下的認證問題;減輕服務(wù)器端的存儲壓力;
缺點:需要自己實現(xiàn)。生成令牌、客戶端存儲令牌、傳輸?shù)椒?wù)端;
JWT令牌:JSON WEB TOKEN
定義了一種簡介的、自包含的格式,用于在通信雙方以json數(shù)據(jù)格式安全的傳輸信息。由于數(shù)字簽名的存在,這些信息是可靠的。
例:共三部分,以點分割。****.*****.****
eyJhbGciOiJIUzI1NiJ9.eyJpZCI6MSwiZXhwIjoxNjkzMTQ5Njc4LCJ1c2VybmFtZSI6IkhhaGFoYSJ9.lzPlLTFHzjq_oEyRqC4Jkz-vAvQs-_kX0Ik9UjBS-98
****.*****,前兩段可以通過base64解碼
組成:
第一部分:Header(頭),記錄令牌類型、簽名算法等。例如:{"alg":"HS256", "type":"JWT"}
第二部分:Payload(有效荷載),攜帶一些自定義信息、默認信息等。例如:{"id":"1", "username":"hahaha"}
第三部分:Signature(簽名),防止Token被篡改、確保安全性。將header、payload,并加入指定秘鑰,通過指定簽名算法計算而來。
登錄認證使用令牌技術(shù):
1、客戶端瀏覽器發(fā)起請求,服務(wù)端登錄成功,生成令牌,將令牌返回給客戶端瀏覽器。
2、客戶端瀏覽器保存令牌。后續(xù)每個請求,都攜帶JWT令牌,服務(wù)端每次請求處理之前,先校驗令牌再處理。
客戶端發(fā)送時放在Head的token中:jwt令牌字符
令牌的生成:引入依賴、書寫以下代碼
HashMap<String, Object> claims = new HashMap<>();
claims.put("id", 1); claims.put("username","Hahaha");
String jwtString = Jwts.builder().setClaims(claims)//自定義內(nèi)容(載荷)
.signWith(SignatureAlgorithm.HS256, SIGNING_KEY)//簽名算法,SIGNING_KEY為秘鑰
.setExpiration(new Date(System.currentTimeMillis() + 12 * 3600 * 1000))//12小時有效期,
.compact();
//令牌的獲取
Claims claims =
Jwts.parser().setSigningKey(SIGNING_KEY)//SIGNING_KEY為秘鑰
.parseClaimsJws(jwtString)
.getBody();
九、過濾器Filter
JavaWeb三大組件之一(Servlet程序、Fiflter過濾器、Listener監(jiān)聽器)
過濾器可以把對資源的請求攔截下來,從而實現(xiàn)一些特殊的功能。
比如:
過濾器一般完成一些通用的操作,比如:登錄校驗、統(tǒng)一編碼處理、敏感字符處理等。
Filter快速入門:
1、定義一個Filter類,實現(xiàn)Filter接口,重寫所有方法。
2、配置Filter,F(xiàn)ilter類加上@WebFilter注解,配置攔截資源的路徑。引導(dǎo)類上加@ServletComponentScan開啟Servlet組件支持。
注:
@WebFilter(urlPatterns = "/*") //攔截所有請求:訪問所有資源都會被攔截
@WebFilter(urlPatterns = "/login")//攔截具體路徑
@WebFilter(urlPatterns = "/emps/*")//目錄攔截:/emps目錄下的所有資源
一個Web應(yīng)用中,可以配置多個過濾器,就形成了過濾器鏈。執(zhí)行順序是過濾器類名(字符串)的自然排序。
實操:登錄校驗Filter-流程
1、獲取請求url
2、判斷url中是否包含login,包含則判斷是登錄操作,需要放行。
3、獲取請求頭中的令牌(token)
4、判斷令牌是否存在,如果不存在,返回錯誤結(jié)果(未登錄)。
5、解析token,如果解析失敗,返回錯誤結(jié)果(未登錄)。
6、放行
十、攔截器Interceptor (Spring環(huán)境中的攔截器)
攔截器執(zhí)行流程:瀏覽器--JavaWeb中的Filter--Spring環(huán)境中的DispatcherServlet--Spring環(huán)境中的Interceptor--Spring環(huán)境中的目標資源
概念:動態(tài)攔截方法調(diào)用的機制,類似于Filter過濾器(Filter是JavaWeb的)。Spring框架中提供的,用來動態(tài)攔截控制器方法的執(zhí)行。
作用:攔截請求,在指定的方法調(diào)用前后,根據(jù)業(yè)務(wù)需要執(zhí)行預(yù)先設(shè)定的代碼。
快速入門:
1、定義攔截器類,實現(xiàn)HandlerInterceptor接口,重寫所有方法。
@Component
public class LoginInterceptor implements HandlerInterceptor {}
2、注冊攔截器。
@Configuration
public class WebConfig implements WebMvcConfigurer {
? ? @Autowired
? ? private LoginInterceptor loginInterceptor;
? ? @Override
? ? public void addInterceptors(InterceptorRegistry registry) {
? ? ? ? //指定攔截路徑
? ? ? ? registry.addInterceptor(loginInterceptor).addPathPatterns("/**");
? ? }
}
注:
//指定攔截一級路徑 addPathPatterns("/*");例:攔截/depts、/emps、/login,不攔截/depts/1
//指定攔截任意級路徑 addPathPatterns("/**");例:攔截/depts、/depts/1、/depts/1/2
//指定攔截/depts下的一級路徑 addPathPatterns("/depts/*");例:攔截/depts/1, 不攔截/depts、/depts/1/2
//指定攔截/depts下的任意級路徑 addPathPatterns("/depts/**");例:攔截/depts、/depts/1、/depts/1/2, 不攔截/emps、/login
//指定不攔截哪些路徑 excludePathPatterns("/login");例:不攔截 /login
十一、全局異常處理器
@RestControllerAdvice
public class GlobalExceptionHandler {
? ? @ExceptionHandler(Exception.class)
? ? public Result ex(Exception e) {
? ? ? ? e.printStackTrace();
? ? ? ? return Result.error("服務(wù)繁忙,請稍后再試!");
? ? }
}
十二、谷歌驗證碼的使用Kaptcha
1、導(dǎo)入kaptcha的jar包(kaptcha-2.3.2.jar)
2、在web.xml中配置用于生成驗證碼的servlet程序,也就是KaptchaServlet
3、在表單中使用image使用kaptcha生成的圖片地址。
4、在服務(wù)器獲取谷歌生成的驗證碼。request.getSession().getAttribute(KAPTCHA_SESSION_KEY);
5、獲取之后立馬刪除removeAttribute
6、request.getParam獲取到請求中的驗證碼與谷歌生成的驗證碼比較即可。