一、什么是過(guò)濾器
過(guò)濾器是Servlet的高級(jí)特性之一,是實(shí)現(xiàn)Filter接口的Java類(lèi)!
過(guò)濾器的執(zhí)行流程:
?
從上面的圖我們可以發(fā)現(xiàn),當(dāng)瀏覽器發(fā)送請(qǐng)求給服務(wù)器的時(shí)候,先執(zhí)行過(guò)濾器,然后才訪問(wèn)Web的資源。服務(wù)器響應(yīng)Response,從Web資源抵達(dá)瀏覽器之前,也會(huì)途徑過(guò)濾器。
過(guò)濾器的用途:過(guò)濾一些敏感的字符串【規(guī)定不能出現(xiàn)敏感字符串】、避免中文亂碼【規(guī)定Web資源都使用UTF-8編碼】、權(quán)限驗(yàn)證【規(guī)定只有帶Session或Cookie的瀏覽器,才能訪問(wèn)web資源】等等等。
也就是說(shuō):當(dāng)需要限制用戶(hù)訪問(wèn)某些資源時(shí)、在處理請(qǐng)求時(shí)提前處理某些資源、服務(wù)器響應(yīng)的內(nèi)容對(duì)其進(jìn)行處理再返回、我們就是用過(guò)濾器來(lái)完成的!
二、過(guò)濾器的一般用途
1.解決中文亂碼問(wèn)題
只要在過(guò)濾器中指定了編碼,可以使全站的Web資源都是使用該編碼,并且重用性是非常理想的!
public class CharacterEncodingFilter implements Filter {
@Override
public void destroy() {
// TODO Auto-generated method stub
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
request.setCharacterEncoding("utf-8");
chain.doFilter(request, response);
}
@Override
public void init(FilterConfig arg0) throws ServletException {
// TODO Auto-generated method stub
}
}
web.xml配置:
<filter>
<filter-name> CharacterEncodingFilter</filter-name>
<filter-class>com.entor.filter.CharacterEncodingFilter</filter-class>
</filter>
<filter-mapping>
<filter-name> CharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
2.過(guò)濾器 API
只要Java類(lèi)實(shí)現(xiàn)了Filter接口就可以稱(chēng)為過(guò)濾器!Filter接口的方法也十分簡(jiǎn)單:
其中init()和destory()方法就不用多說(shuō)了,他倆跟Servlet是一樣的。只有在Web服務(wù)器加載和銷(xiāo)毀的時(shí)候被執(zhí)行,只會(huì)被執(zhí)行一次!
值得注意的是doFilter()方法,它有三個(gè)參數(shù)(ServletRequest,ServletResponse,FilterChain),從前兩個(gè)參數(shù)我們可以發(fā)現(xiàn):過(guò)濾器可以完成任何協(xié)議的過(guò)濾操作!
FilterChain是一個(gè)接口,里面又定義了doFilter()方法。這究竟是怎么回事啊??????
我們可以這樣理解:過(guò)濾器不單單只有一個(gè),那么我們?cè)趺垂芾磉@些過(guò)濾器呢?在Java中就使用了鏈?zhǔn)浇Y(jié)構(gòu)。把所有的過(guò)濾器都放在FilterChain里邊,如果符合條件,就執(zhí)行下一個(gè)過(guò)濾器(如果沒(méi)有過(guò)濾器了,就執(zhí)行目標(biāo)資源)。
上面的話好像有點(diǎn)拗口,我們可以想象生活的例子:現(xiàn)在我想在茶杯上能過(guò)濾出石頭和茶葉出來(lái)。石頭在一層,茶葉在一層。所以茶杯的過(guò)濾裝置應(yīng)該有兩層濾網(wǎng)。這個(gè)過(guò)濾裝置就是FilterChain,過(guò)濾石頭的濾網(wǎng)和過(guò)濾茶葉的濾網(wǎng)就是Filter。在石頭濾網(wǎng)中,茶葉是屬于下一層的,就把茶葉放行,讓茶葉的濾網(wǎng)過(guò)濾茶葉。過(guò)濾完茶葉了,剩下的就是茶(茶就可以比喻成我們的目標(biāo)資源)
三、快速入門(mén)
寫(xiě)一個(gè)簡(jiǎn)單的過(guò)濾器
實(shí)現(xiàn)Filter接口的Java類(lèi)就被稱(chēng)作為過(guò)濾器
public class FilterDemo1 implements Filter {
public void destroy() {
}
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
//執(zhí)行這一句,說(shuō)明放行(讓下一個(gè)過(guò)濾器執(zhí)行,如果沒(méi)有過(guò)濾器了,就執(zhí)行執(zhí)行目標(biāo)資源)
chain.doFilter(req, resp);
}
public void init(FilterConfig config) throws ServletException {
}
}
1.filter部署
過(guò)濾器和Servlet是一樣的,需要部署到Web服務(wù)器上的。
- 第一種方式:在web.xml文件中配置
<filter>
<filter-name>FilterDemo1</filter-name>
<filter-class>FilterDemo1</filter-class>
<init-param>
<param-name>word_file</param-name>
<param-value>/WEB-INF/word.txt</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>FilterDemo1</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter>用于注冊(cè)過(guò)濾器
- <filter-name>用于為過(guò)濾器指定一個(gè)名字,該元素的內(nèi)容不能為空。
- <filter-class>元素用于指定過(guò)濾器的完整的限定類(lèi)名。
- <init-param>元素用于為過(guò)濾器指定初始化參數(shù),它的子元素
<filter-mapping>元素用于設(shè)置一個(gè)Filter 所負(fù)責(zé)攔截的資源。
- <filter-name>子元素用于設(shè)置filter的注冊(cè)名稱(chēng)。該值必須存在
- <url-pattern>設(shè)置 filter 所攔截的請(qǐng)求路徑(過(guò)濾器關(guān)聯(lián)的URL樣式)
- 第二種方式:通過(guò)注解配置
//@Component//無(wú)需添加此注解,在啟動(dòng)類(lèi)添加@ServletComponentScan注解后,會(huì)自動(dòng)將帶有@WebFilter的注解進(jìn)行注入!
@WebFilter(urlPatterns = "/lvjia/carbodyad/api/*", filterName = "rest0PubFilter")
@Order(1)//指定過(guò)濾器的執(zhí)行順序,值越大越靠后執(zhí)行
public class Rest0PubFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) {//初始化過(guò)濾器
System.out.println("getFilterName:"+filterConfig.getFilterName());//返回<filter-name>元素的設(shè)置值。
System.out.println("getServletContext:"+filterConfig.getServletContext());//返回FilterConfig對(duì)象中所包裝的ServletContext對(duì)象的引用。
System.out.println("getInitParameter:"+filterConfig.getInitParameter("cacheTimeout"));//用于返回在web.xml文件中為Filter所設(shè)置的某個(gè)名稱(chēng)的初始化的參數(shù)值
System.out.println("getInitParameterNames:"+filterConfig.getInitParameterNames());//返回一個(gè)Enumeration集合對(duì)象。
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
FilterChain filterChain) throws IOException, ServletException {
if(false){
response.sendRedirect("http://localhost:8081/demo/test/login");//重定向
}
filterChain.doFilter(servletRequest, servletResponse);//doFilter將請(qǐng)求轉(zhuǎn)發(fā)給過(guò)濾器鏈下一個(gè)filter , 如果沒(méi)有filter那就是你請(qǐng)求的資源
}
@Override
public void destroy() {
}
}
@SpringBootApplication
@ServletComponentScan //Servlet、Filter、Listener 可以直接通過(guò) @WebServlet、@WebFilter、@WebListener 注解自動(dòng)注冊(cè),無(wú)需其他代碼。
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
?
@WebFilter常用屬性
屬性 | 類(lèi)型 | 是否必需 | 說(shuō)明 |
---|---|---|---|
asyncSupported | boolean | 否 | 指定Filter是否支持異步模式 |
dispatcherTypes | DispatcherType[] | 否 | 指定Filter對(duì)哪種方式的請(qǐng)求進(jìn)行過(guò)濾。支持的屬性:ASYNC、ERROR、FORWARD、INCLUDE、REQUEST;默認(rèn)過(guò)濾所有方式的請(qǐng)求 |
filterName | String | 否 | Filter名稱(chēng) |
initParams | WebInitParam[] | 否 | 配置參數(shù) |
displayName | String | 否 | Filter顯示名 |
servletNames | String[] | 否 | 指定對(duì)哪些Servlet進(jìn)行過(guò)濾 |
urlPatterns/value | String[] | 否 | 兩個(gè)屬性作用相同,指定攔截的路徑 |
過(guò)濾器的urlPatterns的過(guò)濾路徑規(guī)則:
- 全路徑匹配: /abc/myServlet1.do
- 部分路徑匹配: /abc/*
- 通配符匹配 :/*
- 后綴名匹配 :*.do (注意:前面不加/)
2.過(guò)濾器的執(zhí)行順序
上面已經(jīng)說(shuō)過(guò)了,過(guò)濾器的doFilter()方法是極其重要的,F(xiàn)ilterChain接口是代表著所有的Filter,F(xiàn)ilterChain中的doFilter()方法決定著是否放行下一個(gè)過(guò)濾器執(zhí)行(如果沒(méi)有過(guò)濾器了,就執(zhí)行目標(biāo)資源)。
四、Filter簡(jiǎn)單應(yīng)用
filter的三種典型應(yīng)用:
- 可以在filter中根據(jù)條件決定是否調(diào)用chain.doFilter(request, response)方法,即是否讓目標(biāo)資源執(zhí)行
- 在讓目標(biāo)資源執(zhí)行之前,可以對(duì)request\response作預(yù)處理,再讓目標(biāo)資源執(zhí)行
- 在目標(biāo)資源執(zhí)行之后,可以捕獲目標(biāo)資源的執(zhí)行結(jié)果,從而實(shí)現(xiàn)一些特殊的功能
1.禁止瀏覽器緩存所有動(dòng)態(tài)頁(yè)面
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
//讓W(xué)eb資源不緩存,很簡(jiǎn)單,設(shè)置http中response的請(qǐng)求頭即可了!
//我們使用的是http協(xié)議,ServletResponse并沒(méi)有能夠設(shè)置請(qǐng)求頭的方法,所以要強(qiáng)轉(zhuǎn)成HttpServletRequest
//一般我們寫(xiě)Filter都會(huì)把他倆強(qiáng)轉(zhuǎn)成Http類(lèi)型的
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) resp;
response.setDateHeader("Expires", -1);
response.setHeader("Cache-Control", "no-cache");
response.setHeader("Pragma", "no-cache");
//放行目標(biāo)資源的response已經(jīng)設(shè)置成不緩存的了
chain.doFilter(request, response);
}
-
沒(méi)有過(guò)濾之前,響應(yīng)頭是這樣的:
? -
過(guò)濾之后,響應(yīng)頭是這樣的:
?
2.實(shí)現(xiàn)自動(dòng)登陸文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-676893.html
- 實(shí)體:
private String username ;
private String password;
public User() {
}
public User(String username, String password) {
this.username = username;
this.password = password;
}
//各種setter和getter
- 集合模擬數(shù)據(jù)庫(kù)
public class UserDB {
private static List<User> users = new ArrayList<>();
static {
users.add(new User("aaa", "123"));
users.add(new User("bbb", "123"));
users.add(new User("ccc", "123"));
}
public static List<User> getUsers() {
return users;
}
public static void setUsers(List<User> users) {
UserDB.users = users;
}
}
- 開(kāi)發(fā)dao
public User find(String username, String password) {
List<User> userList = UserDB.getUsers();
//遍歷List集合,看看有沒(méi)有對(duì)應(yīng)的username和password
for (User user : userList) {
if (user.getUsername().equals(username) && user.getPassword().equals(password)) {
return user;
}
}
return null;
}
- 登陸界面
<form action="${pageContext.request.contextPath}/LoginServlet">
用戶(hù)名<input type="text" name="username">
<br>
密碼<input type="password" name="password">
<br>
<input type="radio" name="time" value="10">10分鐘
<input type="radio" name="time" value="30">30分鐘
<input type="radio" name="time" value="60">1小時(shí)
<br>
<input type="submit" value="登陸">
</form>
- 處理登陸的Servlet
//得到客戶(hù)端發(fā)送過(guò)來(lái)的數(shù)據(jù)
String username = request.getParameter("username");
String password = request.getParameter("password");
UserDao userDao = new UserDao();
User user = userDao.find(username, password);
if (user == null) {
request.setAttribute("message", "用戶(hù)名或密碼是錯(cuò)的!");
request.getRequestDispatcher("/message.jsp").forward(request, response);
}
//如果不是為空,那么在session中保存一個(gè)屬性
request.getSession().setAttribute("user", user);
request.setAttribute("message", "恭喜你,已經(jīng)登陸了!");
//如果想要用戶(hù)關(guān)閉了瀏覽器,還能登陸,就必須要用到Cookie技術(shù)了
Cookie cookie = new Cookie("autoLogin", user.getUsername() + "." + user.getPassword());
//設(shè)置Cookie的最大聲明周期為用戶(hù)指定的
cookie.setMaxAge(Integer.parseInt(request.getParameter("time")) * 60);
//把Cookie返回給瀏覽器
response.addCookie(cookie);
//跳轉(zhuǎn)到提示頁(yè)面
request.getRequestDispatcher("/message.jsp").forward(request, response);
- 過(guò)濾器
HttpServletResponse response = (HttpServletResponse) resp;
HttpServletRequest request = (HttpServletRequest) req;
//如果用戶(hù)沒(méi)有關(guān)閉瀏覽器,就不需要Cookie做拼接登陸了
if (request.getSession().getAttribute("user") != null) {
chain.doFilter(request, response);
return;
}
//用戶(hù)關(guān)閉了瀏覽器,session的值就獲取不到了。所以要通過(guò)Cookie來(lái)自動(dòng)登陸
Cookie[] cookies = request.getCookies();
String value = null;
for (int i = 0; cookies != null && i < cookies.length; i++) {
if (cookies[i].getName().equals("autoLogin")) {
value = cookies[i].getValue();
}
}
//得到Cookie的用戶(hù)名和密碼
if (value != null) {
String username = value.split("\\.")[0];
String password = value.split("\\.")[1];
UserDao userDao = new UserDao();
User user = userDao.find(username, password);
if (user != null) {
request.getSession().setAttribute("user", user);
}
}
chain.doFilter(request, response);
- 效果:
文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-676893.html
到了這里,關(guān)于[Java]過(guò)濾器(Filter)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!