過濾器和監聽器
文章目錄
1. 過濾器
1.1 過濾器定義
//也可以通過註解配置filter:@WebFilter("/*"),攔截所有請求
public class EncodFilter implements Filter {
//初始化的方法,可以通過FilterConfig獲得xml配置的參數
@Override
public void init(FilterConfig filterConfig) throws ServletException {}
//過濾器處理業務的方法,完成業務處理之後一定要放行。
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
//放行
filterChain.doFilter(req,resp);
}
//銷燬filter時執行的方法
@Override
public void destroy() {}
}
1.2 過濾器配置
<filter>
<filter-name>encode</filter-name>
<filter-class>com.yogie.lesson.filter.EncodFilter</filter-class>
//配置參數
<init-param>
<param-name>encoding</param-name>
<param-value>utf-8</param-value>
</init-param>
<init-param>
<param-name>force</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encode</filter-name>
//配置過濾路徑:所有請求都要經過encode過濾器
<url-pattern>/*</url-pattern>
</filter-mapping>
1.3 過濾器的生命週期
啓動tomcat的時候開始,先創建FilterConfig,再調用init方法,filter是單例模式,只有一個對象。關閉tomcat服務器或者停止虛擬機運行的時候,過濾器調用destroy方法。
1.4 過濾器的應用
1、對字符進行編碼。
<filter>
<filter-name>encoding</filter-name>
<filter-class>com.yogie.lesson.filter.EncodingFilter</filter-class>
<init-param>
<param-name>charset</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>force</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>encoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
public class EncodingFilter implements Filter {
private String charset;
private Boolean force;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
//讀取配置文件中filter中的配置
charset = filterConfig.getInitParameter("charset");
//如果用戶沒有配置編碼方式
if(charset==null || "".equals(charset)){
//設置一個默認的編碼
charset = "UTF-8";
}
//Boolean.parseBoolean(null)的結果也爲false
force = Boolean.parseBoolean(filterConfig.getInitParameter("force"));
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) servletRequest;
HttpServletResponse resp = (HttpServletResponse)servletResponse;
//獲取請求對象攜帶過來的編碼方式
String ce = req.getCharacterEncoding();
if( ce==null || "".equals(ce) || force){
//如果request請求中沒有設置編碼方式,
//如果配置了強制使用配置中的編碼方式
req.setCharacterEncoding(charset);
}
filterChain.doFilter(req,resp);
}
@Override
public void destroy() {
}
}
2、讓瀏覽器不緩存。
3、屏蔽非法文字(敏感詞過濾處理)。
- 關鍵字過濾器
@WebFilter("/*")
public class SensitiveFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
//將servletRequest轉換成HttpServletRequest對象
HttpServletRequest req = (HttpServletRequest)servletRequest;
//HttpServletRequest轉換成MyHttpRequestWapper,
//在這個轉換的過程中,請求對象所攜帶的文本信息中的敏感信息被過濾掉了
MyHttpRequestWapper requestWapper = new MyHttpRequestWapper(req);
//放行後,request對象已經是經過包裝的request對象了
filterChain.doFilter(requestWapper, servletResponse);
}
@Override
public void destroy() {
}
}
- 請求對象的裝飾類
public class MyHttpRequestWapper extends HttpServletRequestWrapper {
private HttpServletRequest req = null;
public MyHttpRequestWapper(HttpServletRequest request) {
//必須顯示調用父類的構造方法,因爲父類沒有默認的無參構造方法
super(request);
//將HttpServletRequest對象賦值給字段
req = request;
}
@Override
public String getParameter(String name) {
//根據參數名獲取請求對象中的對應的值
String value = req.getParameter(name);
return SensitiveUtil.filterWords(value,"*");
}
@Override
public Map<String, String[]> getParameterMap() {
//獲取請求對象中的鍵值對map
Map<String, String[]> map = req.getParameterMap();
//準備一個返回的map
Map<String, String[]> result = new HashMap<>();
//取出其中所有的鍵值對集合
Set<Map.Entry<String, String[]>> entries = map.entrySet();
//遍歷集合
for (Map.Entry<String, String[]> entry : entries) {
//key
String key = entry.getKey();
//value:有的字段可能對應多個值,例如select標籤
String[] value = entry.getValue();
//設計一個與value一致長度的數組
String[] arr = new String[value.length];
//遍歷這個vlaue數組,將數組中每個元素的字符串都進行敏感詞過濾
for (int i = 0; i < value.length; i++) {
arr[i] = SensitiveUtil.filterWords(value[i],"*");
}
//將過濾後的值保存到map集合中
result.put(key,arr);
}
return result;
}
}
- 敏感詞替換的工具類
public class SensitiveUtil {
private static List<String> keyWords = new ArrayList<>();
static{
Scanner sc = new Scanner(Thread.currentThread().getContextClassLoader().getResourceAsStream("sensitive.txt"),"UTF-8");
while (sc.hasNextLine()){
String line = sc.nextLine();
if(line!=null || !"".equals(line)){
keyWords.add(line);
}
}
sc.close();
}
/**
* 將str中的敏感詞替換爲指定字符拼接成的字符串
* @param str
* @param mask
* @return
*/
public static String filterWords(String str,String mask){
for (String keyWord : keyWords) {
if(str!=null && str.indexOf(keyWord) >= 0){
str = str.replaceAll(keyWord,buildMask(keyWord,mask));
}
}
return str;
}
/**
* 配置keyword長度的替代字符
* @param keyWord
* @param mask
* @return
*/
private static String buildMask(String keyWord, String mask) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < keyWord.length(); i++) {
sb.append(mask);
}
return sb.toString();
}
}
4、登錄權限驗證。
- 登錄權限的過濾器
public class LoginFilter implements Filter {
String[] strs = null;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
//將配置中不用驗證的資源放入strs數組中
strs = filterConfig.getInitParameter("outs").split(",");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) servletRequest;
HttpServletResponse resp = (HttpServletResponse) servletResponse;
//從session中獲得key爲username的對象
Object obj = req.getSession().getAttribute("NAME_IN_SESSION");
//獲取到請求路徑中的uri描述,並按照反斜槓分割
String[] split = req.getRequestURI().split("/");
//將配置中的路徑放到list中
List<String> list = Arrays.asList(strs);
//如果配置的路徑中不包含此次請求資源且session爲空,不能放行
if(!list.contains(split[split.length-1]) && obj==null){
resp.sendRedirect("/xx/index.html");
return;
}
//放行
filterChain.doFilter(req,resp);
}
@Override
public void destroy() {
}
}
- 配置
<filter>
<filter-name>login</filter-name>
<filter-class>com.yogie.lesson.filter.LoginFilter</filter-class>
<init-param>
<param-name>outs</param-name>
<!--除了這兩個資源,其他都要驗證權限-->
<param-value>index.html,login</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>login</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
- 登錄的servlet
@WebServlet("/login")
public class LoginServlet extends HttpServlet{
StudentDao dao = new StudentDaoImpl();
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
Student stu = BeanUtil.getBean(req, Student.class);
Student stu1 = dao.queryByUsernameAndPassword(stu.getUsername(),stu.getPassword());
if(stu1!=null){
//登錄成功,將用戶名存入session
req.getSession().setAttribute("NAME_IN_SESSION",stu.getUsername());
//跳轉到系統列表
resp.sendRedirect("/xx/controller?cmd=query");
}else{
//登錄失敗,返回登錄頁面
resp.sendRedirect("/xx/index.html");
}
}
}
5、請求分發器。
6、頁面僞靜態化處理。
2. 過濾器鏈
多個過濾器鍊形成的一組過濾器,然後我們在訪問最終的資源的時候會經過這一組過濾器,在返回的時候還會經過這一組過濾器。過濾器鏈的執行順序是按照filter-mapping的順序執行的。
3. FilterConfig對象
String getFilterName(); 獲取filter的名稱(配置的name)。
ServletContext getServletContext(); 獲得web項目的上下文對象。
String getInitParameter(String var1); 根據參數名獲取filter配置中的init-param的value。
Enumeration<String> getInitParameterNames(); 獲取所有參數配置的name。
4. 特殊的請求過濾
4.1 請求轉發過濾
<filter-mapping>
<filter-name>a</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>FORWARD</dispatcher>
</filter-mapping>
4.2 重定向過濾
<filter-mapping>
<filter-name>b</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REDIRECT</dispatcher>
</filter-mapping>
4.3 默認情況
<filter-mapping>
<filter-name>b</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
</filter-mapping>
5. 監聽器
在web中,監聽器的監聽內容一般有:
1、監聽四大作用的生命週期(主要是創建與銷燬)。
2、監聽作用域屬性的變化(主要是增刪改查)。
5.1 作用域監聽器接口
ServletRequestListener -> 對request作用域監聽器
HttpSessionListener -> 對session作用域監聽器
ServletContextListener -> 對application作用域監聽器
ServletRequestAttributeListener -> 對request作用域的屬性監聽器
HttpSessionAttibuteListener -> 對session作用域的屬性監聽器
ServletContextAttributeListener -> 對application作用域的屬性監聽器
需要創建哪一種監聽器,就去實現對應的接口。
5.2 監聽器的配置
<listener>
<listener-class>com.yogie.filter.MyFilter</listener-class>
</listener>