??詳細介紹了Java Web Servlet中的Filter過濾器的原理以及常見用法,
文章目錄
- 1 Filter介面
- 1.1 過濾器的生命周期
- 1.2 doFilter過濾方法
- 2 Filter的使用
- 3 Filter的執行順序
- 3.1 多個過濾器
- 4 Filter的應用
- 4.1 臟話過濾器
- 4.2 編碼過濾器
- 4.3 統計IP訪問次數
- 4.4 禁止動態資源快取的過濾器
- 4.5 html標記過濾器
??過濾器屬于Servlet規范,從2.3版本就開始有了,主要用于對到資源的請求或來自資源的回應執行過濾、篩選操作,
??當存在過濾器的時候,對于來自客戶端的請求來說,請求必須先經過濾器,放行之后,才能到達Web資源;對于回傳的回應來說,回應同樣會經過濾器,才能到達Web服務器,進而回應給客戶端

??過濾器可以做很多事情,常見的包括:
- 過濾臟敏感字符(綠一些敏感的字串);
- 避免中文亂碼(統一設定請求和回應的編碼);
- 權限驗證(規定只有帶指定Session或Cookie的請求,才能訪問資源);
- 用于實作自動登錄;
1 Filter介面
??過濾器在Java中對應著javax.servlet.Filter介面,僅此而已,實作了Filter介面的類就可以被稱作過濾器,就是這么簡單,
??Filter介面中有三個抽象方法,其中init和destroy方法作為過濾器的申請周期方法!
public interface Filter {
default public void init(FilterConfig filterConfig) throws ServletException {}
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain)
throws IOException, ServletException;
default public void destroy() {}
}
1.1 過濾器的生命周期
誕生:過濾器的實體是在web應用被加載時就完成的實體化,并呼叫init方法初始化的,servlet 容器在實體化Filter后只呼叫init方法一次,在要求過濾器執行任何過濾作業之前,init 方法必須成功完成,區別于Servlet,過濾器會全部立即初始化,- 每個過濾器在init初始化方法都會傳遞一個 FilterConfig 物件,從該物件可以獲取其初始化引數,并可通過FilterConfig獲取 ServletContext物件,比如可以使用該物件加載篩選任務所需的資源,
存活:和應用的生命周期一致的,在記憶體中是單例的,針對攔截范圍內的資源,每次訪問都會呼叫void doFIlter(request,response.chain)進行攔截,死亡:應用被卸載時,Filter將被呼叫,此時會呼叫destroy方法,該方法只會被呼叫一次,
1.2 doFilter過濾方法
??過濾器在 doFilter 方法中執行過濾操作,
??doFilter方法中有一個FilterChain 引數物件,該物件由Servlet容器創建并傳遞給開發人員的,FilterChain表示一個過濾器鏈,客戶端請求的資源在鏈的末尾,
??在當前過濾器中,如果復合過濾規則,那么可以使用 FilterChain 的doFilter方法呼叫鏈中的下一個過濾器器,或者如果呼叫過濾器是鏈中的最后一個過濾器,則該方法將呼叫鏈末尾的資源,
??也就是說,一個Web應用中可以有多個過濾器,它們將會按照一定順序形成一個過濾器鏈,在鏈的最末尾就是要訪問的資源,當一個請求到來的時候,他必須通過所有的過濾器,才能訪問到真正的資源,
2 Filter的使用
??開發一個過濾器很簡單,只需要實作Filter介面,實作doFilter方法,
public class FirstFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) {
System.out.println("init");
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
System.out.println("放行前");
HttpServletRequest httpServletRequest= (HttpServletRequest) request;
//獲取當前請求的URL
System.out.println(httpServletRequest.getRequestURL());
//放行,呼叫下一個過濾器或者訪問資源
chain.doFilter(request, response);
System.out.println("放行后");
}
@Override
public void destroy() {
System.out.println("destroy");
}
}
??隨后我們還需要部署這個filter,通常情況下,Filter過濾器在 Web 應用程式的部署描述符中配置,也就是web.xml檔案,這類似于Servlet,
??首先是定義一個Filter:
<filter>
<filter-name>FirstFilter</filter-name>
<filter-class>com.example.filter.FirstFilter</filter-class>
<!--當前過濾器的初始化引數,可以通過在init方法的引數FilterConfig物件獲取-->
<init-param>
<param-name>aaa</param-name>
<param-value>bbb</param-value>
</init-param>
<init-param>
<param-name>ccc</param-name>
<param-value>ddd</param-value>
</init-param>
</filter>
??一個<filter/>標簽表示定義一個過濾器,<filter-name/>表示當前過濾器的name,<filter-class/>表示當前過濾器的類全路徑名,<init-param/>表示當前過濾器的初始化引數,可以通過在init方法的引數FilterConfig物件獲取這些引數,
??隨后我們還需要定義這個過濾器可以作用于哪些資源或者哪些Servlet!
<filter-mapping>
<filter-name>FirstFilter</filter-name>
<!--指定攔截指定路徑的資源URL-->
<url-pattern>/aa/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>FirstFilter</filter-name>
<!--指定攔截指定的ServletName-->
<servlet-name>Servlet2</servlet-name>
<!--調度程式-->
<!--<dispatcher>REQUEST</dispatcher>-->
</filter-mapping>
??通過多個<filter-mapping/>標簽可以為一個過濾器配置多個過濾映射,當然也可以將多個映射一個到一個<filter-mapping/>標簽中
<filter-name/>指定某個過濾器的名字<url-pattern/>指定過濾器所攔截的資源路徑URL,“/”表示所有的Web資源都需要途徑該過濾器,“.xxx”表示攔截訪問xxx后綴的資源的請求,<servlet-name/>指定過濾器所攔截的某個Servlet的名字,<dispatcher/>指定過濾器在攔截時所應用的調度模式,一共有五個可選配置:FORWARD, REQUEST, INCLUDE, ASYNC, ERROR,FORWARD:如果目標資源是通過RequestDispatcher的forward()方法訪問的,那么該過濾器將被呼叫,除此之外,該過濾器不會被呼叫,REQUEST:當用戶直接通過普通路徑訪問資源時,Web容器將會呼叫過濾器,如果目標資源是通過RequestDispatcher的include()或forward()方法訪問時,那么該過濾器就不會被呼叫,這是默認的模式,INCLUDE:如果目標資源是通過RequestDispatcher的include()方法訪問的,那么該過濾器將被呼叫,除此之外,該過濾器不會被呼叫,ERROR:如果目標資源是通過宣告式的例外處理機制呼叫的,那么該過濾器將被呼叫,除此之外,過濾器不會被呼叫,SYNC:意味著過濾器將在從異步上下文AsyncContext的呼叫下應用,
??在Servlet 3.0以及之后,支持在Filter實作類上直接使用@WebFilter注解的方式配置過濾器,降低了組態檔的復雜度,例如:
@WebFilter(urlPatterns = "/aa/*",servletNames = "Servlet2")
??下面簡單測驗,如下有三個Servlet:
@WebServlet(name = "Servlet1", value = "/aa/Servlet1")
public class Servlet1 extends HttpServlet {
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
System.out.println("請求到達");
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
out.println("Servlet1");
}
}
@WebServlet(name = "Servlet2", value = "/bb/Servlet2")
public class Servlet2 extends HttpServlet {
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
System.out.println("請求到達");
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
out.println("Servlet2");
}
}
@WebServlet(name = "Servlet3", value = "/bb/Servlet3")
public class Servlet3 extends HttpServlet {
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
System.out.println("請求到達");
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();
out.println("Servlet3");
}
}
??如果我們采用上面的過濾器設定,那么在訪問Servlet1和Servlet2的時候,將會經過過濾器,而訪問Servlet3的時候則不會經過過濾器,控制臺輸出為:

??如果我們注釋掉chain.doFilter方法,即不放行,那么訪問Servlet1和Servlet2的時候,頁面上不會有任何輸出,也不會輸出控制臺也不會輸出“請求到達”字串,因為請求被攔截了,而訪問Servlet3的時候則可以正常訪問:

3 Filter的執行順序
??上面的簡單測驗,我們可能會發現,在chain.doFilter之前的邏輯在請求到達指定的Servlet之前執行,chain.doFilter之后的邏輯則是在請求到達指定的Servlet并離開之后執行,
??過濾器鏈的完整流程順序是這樣的:客戶端發送http請求到Web服務器上,Web服務器對該請求URL找到對應負責的過濾器形成過濾器鏈,接著從第一個過濾器開始進行過濾操作,也就是呼叫Filter.doFilter方法,這個方法的邏輯是開發者撰寫的,當當前請求滿足當前過濾器的要求或者是過濾操作完畢之后,應在呼叫chain.doFilter方法進行放行,該方法又會呼叫鏈中的下一個過濾器的doFilter方法繼續過濾,如果當前過濾器是過濾器鏈的最后一個過濾器,那么chain.doFilter方法將會執行資源訪問操作,訪問完畢之后,將會依照最開始過濾器的呼叫順序倒序的回傳,接著執行chain.doFilter方法后面的代碼,最終將回應結果交給Web服務器,Web服務器再將回應回傳給客戶端,
3.1 多個過濾器
??當某個請求對應存在多個過濾器時,過濾器之間的執行順序是通過在web.xml檔案中某個Filter的首個<filter-mapping/>定義的先后順序決定的,
??如下,兩個Filter:
public class Filter1 implements Filter {
@Override
public void init(FilterConfig filterConfig) {
System.out.println("Filter1-init");
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
System.out.println("-----Filter1放行前-----");
HttpServletRequest httpServletRequest= (HttpServletRequest) request;
//獲取當前請求的URL
System.out.println(httpServletRequest.getRequestURL());
//放行,呼叫下一個過濾器或者訪問資源
chain.doFilter(request, response);
System.out.println("-----Filter1放行后-----");
}
@Override
public void destroy() {
System.out.println("destroy");
}
}
public class Filter2 implements Filter {
@Override
public void init(FilterConfig filterConfig) {
System.out.println("Filter2-init");
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
System.out.println("-----Filter2放行前-----");
HttpServletRequest httpServletRequest= (HttpServletRequest) request;
//獲取當前請求的URL
System.out.println(httpServletRequest.getRequestURL());
//放行,呼叫下一個過濾器或者訪問資源
chain.doFilter(request, response);
System.out.println("-----Filter2放行后-----");
}
@Override
public void destroy() {
System.out.println("destroy");
}
}
??以下是映射配置:
<filter>
<filter-name>Filter1</filter-name>
<filter-class>com.example.filter.Filter1</filter-class>
</filter>
<filter>
<filter-name>Filter2</filter-name>
<filter-class>com.example.filter.Filter2</filter-class>
</filter>
<!--Filter2的mapping在前-->
<filter-mapping>
<filter-name>Filter2</filter-name>
<!--指定攔截指定的ServletName-->
<servlet-name>Servlet2</servlet-name>
</filter-mapping>
<filter-mapping>
<filter-name>Filter1</filter-name>
<!--指定攔截指定路徑的資源URL-->
<url-pattern>/aa/*</url-pattern>
<!--指定攔截指定的ServletName-->
<servlet-name>Servlet2</servlet-name>
</filter-mapping>
<filter-mapping>
<filter-name>Filter2</filter-name>
<!--指定攔截指定路徑的資源URL-->
<url-pattern>/aa/*</url-pattern>
</filter-mapping>
??可以看到Filter2的mapping在前,因此Filter2將先被執行,但是在資源訪問完畢回傳時,則是倒序執行!
??我們訪問Servlet1和Servlet2,將會得到如下結果:

??如果是通過注解的方式配置,就比較urlPatterns的字串優先級,
4 Filter的應用
??Filter的簡單應用包括:
- 可以在Filter中根據條件決定是否呼叫
chain.doFilter(request,response)方法,即是否讓目標資源能夠訪問, - 在訪問目標資源之前,可以對request\response作預處理,
- 在目標資源訪問之后,可以捕獲目標資源的執行結果,從而實作一些特殊的功能,
4.1 臟話過濾器
??臟話過濾器,將引數中的臟話替換為**,
/**
* 臟話過濾器,攔截所有訪問路徑
*
* @author lx
*/
@WebFilter("/*")
public class DirtyWordsFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) {
System.out.println("DirtyWordsFilter-init");
}
@Override
public void doFilter(ServletRequest req, ServletResponse resp,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest request;
HttpServletResponse response;
try {
request = (HttpServletRequest) req;
response = (HttpServletResponse) resp;
} catch (Exception e) {
throw new RuntimeException("non-http request or response");
}
//傳遞一個裝飾類,該類的getParameter能夠過濾某些臟話
DWHttpServletRequest dwrequest = new DWHttpServletRequest(request);
chain.doFilter(dwrequest, response);
}
@Override
public void destroy() {
System.out.println("destroy");
}
}
/**
* 裝飾類,接收一個request物件
*/
class DWHttpServletRequest extends HttpServletRequestWrapper {
/**
* 臟話詞典
*/
private String[] strs = {"坤坤", "凡凡", "禽獸", "畜生", "傻B"};
public DWHttpServletRequest(HttpServletRequest request) {
super(request);
}
/**
* 增強了getParameter方法
* <p>
* 將引數中的臟話替換為**才回傳
*/
@Override
public String getParameter(String name) {
String value = super.getParameter(name);
if (value == null) {
return value;
}
for (String s : strs) {
//將臟話替換為**才回傳
value = value.replace(s, "**");
}
return value;
}
}
??測驗Servlet:
@WebServlet("/DirtyWordsServlet")
public class DirtyWordsServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
String name = req.getParameter("name");
resp.setContentType("text/html;charset=utf-8");
PrintWriter out = resp.getWriter();
out.println("<h1>" + name + "</h1>");
}
}
??嘗試請求http://localhost:8081/filter/DirtyWordsServlet?name=坤坤,回傳結果如下:

4.2 編碼過濾器
??我們前面說過,tomcat8以下的版本默認對于URL采用iso-8859-1解碼,那么get請求引數具有中文等特殊字符時,獲取引數值的時候需要進行轉碼,并且在對于post請求的引數也需要通過setCharacterEncoding設定編碼,非常麻煩,
??現在有了Filter過濾器,我們可以使用一個Filter解決全部的get請求的亂碼問題,這里涉及到動態代理的應用(tomcat8及其以上不適用,因為tomcat8默認對于URL采用utf-8解碼,可以直接獲取正常的引數值),
??同時,還能統一設定Post請求編碼,以及回應編碼,有了這個過濾器,就不必在各個Servlet中設定請求編碼或者回應編碼了,
??Spring MVC中的CharacterEncodingFilter就是一個編碼過濾器的實作!
@WebFilter("/*")
public class EncodingFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) {
System.out.println("EncodingFilter-init");
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
//將request和response強轉成http協議的
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse resp = (HttpServletResponse) response;
/*
* 通用編碼設定
*/
//解決post請求提交引數的亂碼問題
req.setCharacterEncoding("UTF-8");
//統一設定回應編碼
resp.setContentType("text/html;charset=UTF-8");
//使用JDK的動態代理,動態的增強req物件的getParameter(name)方法
//解決tomcat8一下的版本的get請求url亂碼的問題(tomcat8之后的版本不需要了)
HttpServletRequest myReq = (HttpServletRequest) Proxy.newProxyInstance(HttpServletRequest.class.getClassLoader(), new Class[]{HttpServletRequest.class}, (proxy, method, args) -> {
Object obj;
//如果是getParameter方法被呼叫
if ("getParameter".equalsIgnoreCase(method.getName())) {
//獲取本次的請求方法
String md = req.getMethod();
//解決get請求提交引數的亂碼問題,動態增強
if ("get".equalsIgnoreCase(md)) {
//呼叫目標物件的getParameter方法
String v = (String) method.invoke(req, args);
//對獲取到的結果進行轉碼(tomcat8之后的版本不需要了)
return new String(v.getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.UTF_8);
}
//其他請求
obj = method.invoke(req, args);
}
//如果是其他方法被呼叫,那么直接通過目標物件呼叫
else {
obj = method.invoke(req, args);
}
return obj;
});
//將代理物件放行
chain.doFilter(myReq, response);
}
@Override
public void destroy() {
System.out.println("destroy");
}
}
4.3 統計IP訪問次數
??IP工具類:
/**
* @author lx
*/
public class IpUtil {
/**
* 獲取用戶真實IP地址
*
* @param request 請求
* @return ip
*/
public static String getIpAddr(HttpServletRequest request) {
String ip = request.getHeader("x-forwarded-for");
System.out.println("x-forwarded-for ip: " + ip);
if (ip != null && ip.length() != 0 && !"unknown".equalsIgnoreCase(ip)) {
// 多次反向代理后會有多個ip值,第一個ip才是真實ip
if (ip.contains(",")) {
ip = ip.split(",")[0];
}
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
System.out.println("Proxy-Client-IP ip: " + ip);
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
System.out.println("WL-Proxy-Client-IP ip: " + ip);
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_CLIENT_IP");
System.out.println("HTTP_CLIENT_IP ip: " + ip);
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("HTTP_X_FORWARDED_FOR");
System.out.println("HTTP_X_FORWARDED_FOR ip: " + ip);
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("X-Real-IP");
System.out.println("X-Real-IP ip: " + ip);
}
if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
System.out.println("getRemoteAddr ip: " + ip);
}
System.out.println("獲取客戶端ip: " + ip);
return ip;
}
}
??IP統計過濾器:
/**
* 根據ip統計訪問次數
*
* @author lx
*/
@WebFilter("/*")
public class IPCountFilter implements Filter {
private FilterConfig config;
/**
* 在init方法中初始化一個map集合,用于存放ip以及它們的訪問次數,將map存入ServletContext域物件中
* <p>
* 這個方法只會呼叫一次
*/
@Override
public void init(FilterConfig config) {
this.config = config;
//準備一個map空集合:
Map<String, Integer> map = new HashMap<>();
//將map集合存放在ServletContext域物件當中:
ServletContext context = config.getServletContext();
//存進去:
context.setAttribute("map", map);
}
@Override
public void doFilter(ServletRequest req,
ServletResponse res, FilterChain chain)
throws IOException, ServletException {
/*
* 開發步驟:
* 1:獲得當前請求的ip地址:
* 2:從一個map集合當中進行查詢,
* 如果查詢不到,存1進去,
* 如果查詢到,將值+1后存進去,
* 3:在頁面上展示即可
*/
//強制轉換:
HttpServletRequest request;
HttpServletResponse response;
try {
request = (HttpServletRequest) req;
response = (HttpServletResponse) res;
} catch (ClassCastException e) {
throw new ServletException("non-HTTP request or response");
}
//獲取ip地址
String ip = request.getRemoteAddr();
//從context當中獲得map集合:
ServletContext context = config.getServletContext();
Map<String, Integer> map = (Map<String, Integer>) context.getAttribute("map");
//從map集合當中獲得ip對應的值,并且記錄訪問次數
Integer count = map.computeIfAbsent(ip, s -> 0);
//將值存回map集合當中
map.put(ip, ++count);
//map集合存回ServletContext當中:
context.setAttribute("map", map);
//放行
chain.doFilter(request, response);
}
@Override
public void destroy() {
}
}
??IPCountServlet:
@WebServlet("/IPCountServlet")
public class IPCountServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
resp.setContentType("text/html;charset=utf-8");
PrintWriter out = resp.getWriter();
ServletContext servletContext = getServletContext();
//從context當中獲得map集合:
Map<String, Integer> map = (Map<String, Integer>) servletContext.getAttribute("map");
for (Map.Entry<String, Integer> stringIntegerEntry : map.entrySet()) {
out.println("IP: " + stringIntegerEntry.getKey() + "的訪問次數為: " + stringIntegerEntry.getValue());
}
}
}
??注意,如果是localhost,那么可能將獲取0:0:0:0:0:0:0:1的IPV6的形式地址,對應ipv4來說相當于127.0.0.1,也就是本機,
4.4 禁止動態資源快取的過濾器
??假設動態資源訪問路徑為“/Servlet”和“.JSP”,Servlet、JSP等動態資源不應該被瀏覽器快取,因為回應結果隨時可能改變,
@WebFilter(urlPatterns = {"/servlet/*", "*.jsp"})
public class NocacheFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) {
System.out.println("NocacheFilter-init");
}
@Override
public void doFilter(ServletRequest req, ServletResponse resp,
FilterChain chain) throws IOException, ServletException {
//強制轉換:
HttpServletRequest request;
HttpServletResponse response;
try {
request = (HttpServletRequest) req;
response = (HttpServletResponse) resp;
} catch (ClassCastException e) {
throw new ServletException("non-HTTP request or response");
}
//設定動態資源的過期時間和瀏覽器不快取
response.setHeader("Expires", "-1");
response.setHeader("Cache-Control", "no-cache");
response.setHeader("Pragma", "no-cache");
//放行:
chain.doFilter(request, response);
}
@Override
public void destroy() {
System.out.println("destroy");
}
}
4.5 html標記過濾器
@WebFilter("/*")
public class HTMLFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) {
System.out.println("HTMLFilter-init");
}
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
//增強物件
HTMLHttpServlet htmlHttpServlet = new HTMLHttpServlet((HttpServletRequest) request);
//放行
chain.doFilter(htmlHttpServlet, response);
}
@Override
public void destroy() {
System.out.println("destroy");
}
}
/**
* html標記過濾器,增強類
*/
class HTMLHttpServlet extends HttpServletRequestWrapper {
/**
* Constructs a request object wrapping the given request.
*
* @param request the {@link HttpServletRequest} to be wrapped.
* @throws IllegalArgumentException if the request is null
*/
public HTMLHttpServlet(HttpServletRequest request) {
super(request);
}
/**
* 增強getParameter方法
*/
@Override
public String getParameter(String name) {
String value = super.getParameter(name);
return filter(value);
}
/**
* tomcat 當中webapps/examples專案下的/WEB-INF/classes/utils下的工具類
* <p>
* Filter the specified message string for characters that are sensitive
* in HTML. This avoids potential attacks caused by including JavaScript
* codes in the request URL that is often reported in error messages.
*
* @param message The message string to be filtered
* @return the filtered version of the message
*/
public static String filter(String message) {
if (message == null)
return null;
char content[] = new char[message.length()];
message.getChars(0, message.length(), content, 0);
StringBuilder result = new StringBuilder(content.length + 50);
for (char c : content) {
switch (c) {
case '<':
result.append("<");
break;
case '>':
result.append(">");
break;
case '&':
result.append("&");
break;
case '"':
result.append(""");
break;
default:
result.append(c);
}
}
return result.toString();
}
}
如有需要交流,或者文章有誤,請直接留言,另外希望點贊、收藏、關注,我將不間斷更新各種Java學習博客!
CSDN認證博客專家
Javaer
博客專家
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/258935.html
標籤:java
