Servlet

    技术2022-07-14  103

    Servlet

    文章目录

    Servlet一、C/S和B/S架构1.1 C/S1.2 B/S 二、服务器三、Tomcat服务器3.1 目录结构3.2启动和停止 四、Servlet的使用4.1 Servlet接口、GenericServlet、HTTPServlet的关系4.2 Servlet创建和配置 五、request和response的使用5.1 request的使用5.2 response的使用 六、重定向和请求转发`【重点】`6.1 重定向6.2 请求转发 七、综合案例八、Servlet生命周期九、Servlet线程安全问题十、状态管理10.1 编码和解码10.2cookie的使用10.4 ServletContext 十一、过滤器11.1 创建和配置11.2 过滤器链11.3 过滤器实际应用

    一、C/S和B/S架构

    1.1 C/S

    是指客户端/服务器。

    优点:显示效果比较好,不用下载界面内容等。

    缺点:每次更新需要下载客户端才能使用。

    应用场景:一般应用于大型软件、游戏等。

    1.2 B/S

    是指浏览器/服务器。

    优点:打开浏览器即可访问,更新只是在服务器上进行。

    缺点:显示效果没有C/S好。

    应用场景:基本上企业应用都会使用此架构。

    二、服务器

    注意:web服务器的作用是将程序员编写的web项目加载并运行。由于编写的web项目不能独立运行,而需要放入到web服务器加载运行,所以web项目中没有main方法。

    三、Tomcat服务器

    3.1 目录结构

    许可证:表示当前软件是否可以使用,是否可以商用的许可。

    常见的有Apache License。

    bin:可执行文件。

    conf:配置文件。server.xml是服务器的配置,用得最多。

    lib:tomcat运行需要的jar包。

    logs:日志文件。

    webapps:可运行的web项目。(自己写的项目也是放到此处)ROOT是默认项目,如果把自己的项目放入ROOT中,那么自己项目也可以成为默认项目。实际在企业开发中,会删除掉ROOT里面的内容,或者将自己的项目放入其中。

    work:主要是将JSP转换成servlet代码放入其中。

    3.2启动和停止

    tomcat的启动有两种方式:

    catalina.bat run 是通过控制台(命令行)直接启动,会显示日志和错误信息,关掉该窗口(也可以使用ctrl+C)即为停止。startup.bat 是通过后台运行的方式启动,需要通过shutdown.bat停止。(如果停止不了,需要关闭进程)

    访问方式:本机访问可以通过打开浏览器输入:http://localhost:8080或者http://127.0.0.1:8080,如果其他人要访问,可以使用服务器ip:8080访问。

    修改端口号可以在conf/server.xml中修改。默认为8080

    #####3.3 HTTP协议

    HTTP超文本传输协议。

    基于请求和响应模式,无状态

    三次握手和四次挥手

    三次握手(three-way handshaking)

    1.背景:TCP位于传输层,作用是提供可靠的字节流服务,为了准确无误地将数据送达目的地,TCP协议采纳三次握手策略。

    2.原理:

    1)发送端首先发送一个带有SYN(synchronize)标志地数据包给接收方。

    2)接收方接收后,回传一个带有SYN/ACK标志的数据包传递确认信息,表示我收到了。

    3)最后,发送方再回传一个带有ACK标志的数据包,代表我知道了,表示’握手‘结束。

    四次挥手(Four-Way-Wavehand)

    **1.意义:**当被动方收到主动方的FIN报文通知时,它仅仅表示主动方没有数据再发送给被动方了。但未必被动方所有的数据都完整的发送给了主动方,所以被动方不会马上关闭SOCKET,它可能还需要发送一些数据给主动方后,再发送FIN报文给主动方,告诉主动方同意关闭连接,所以这里的ACK报文和FIN报文多数情况下都是分开发送的。

    2.原理:

    1)第一次挥手:Client发送一个FIN,用来关闭Client到Server的数据传送,Client进入FIN_WAIT_1状态。

    2)第二次挥手:Server收到FIN后,发送一个ACK给Client,确认序号为收到序号+1(与SYN相同,一个FIN占用一个序号),Server进入CLOSE_WAIT状态。

    3)第三次挥手:Server发送一个FIN,用来关闭Server到Client的数据传送,Server进入LAST_ACK状态。

    4)第四次挥手:Client收到FIN后,Client进入TIME_WAIT状态,接着发送一个ACK给Server,确认序号为收到序号+1,Server进入CLOSED状态,完成四次挥手

    长连接和短连接:

    短连接是每次请求和响应都会建立连接和断开连接。

    长连接是指多次请求和响应基于一次连接。在HTTP协议中,1.1版本使用的长连接,在规定时间内,可以完成多次请求和响应,超时断开。

    四、Servlet的使用

    4.1 Servlet接口、GenericServlet、HTTPServlet的关系

    Servlet接口中包含5个方法,关键方法是init、destory、service。如果实现此接口需要实现5个方法,比较麻烦。

    GenericServlet实现了Servlet接口,并对init、destory等方法提供了简单实现。如果继承此类只需要实现service方法即可。

    HTTPServlet专注于HTTP协议。继承了GenericServlet,并重写了service方法。将其请求和响应强转成HTTP协议类型。并且对service方法进行了分发处理。然后定义了doGet、doPost等一系列的分发处理方法。这些方法内容都是直接报错,强制要求子类继承时必须要重写这些方法。(一般重写doGet和doPost方法即可)

    4.2 Servlet创建和配置

    继承HttpServlet并实现方法。

    public class FirstServlet extends HttpServlet{ public FirstServlet(){ System.out.println("create FirstServlet"); } @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("Hello, doGet"); } @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("Hello, doPost"); } }

    Servlet 2.5版本以及之前的配置,主要配置在web.xml中。

    <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd" version="3.1"> <!-- 给Servlet类配置名字--> <servlet> <servlet-name>FirstServlet</servlet-name> <servlet-class>com.qf.day10.servlet.FirstServlet</servlet-class> <load-on-startup>0</load-on-startup> </servlet> <!-- 给Servlet名字绑定路径--> <servlet-mapping> <servlet-name>FirstServlet</servlet-name> <url-pattern>/fs</url-pattern> </servlet-mapping> </web-app>

    Servlet3.0之后简化了配置,可以使用注解配置。

    @WebServlet(value = "/ts", loadOnStartup = 2) // Servlet3.0以上的版本才支持 public class ThirdServlet extends HttpServlet{ public ThirdServlet(){ System.out.println("create ThirdServlet"); } @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("ThirdServlet, doGet"); } @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("ThirdServlet, doPost"); } }

    Servlet默认是在第一次访问的时候创建并初始化对象。

    但是可以通过配置loadOnStartup来改变此设定,以达到启动服务器就创建的目的。

    默认是-1,如果配置为0或者正数,按照数字从小到大顺序来创建对象。

    五、request和response的使用

    5.1 request的使用

    request是封装用户请求的对象。包含请求头和请求正文(具体内容参考请求报文)

    常用的方法有两个:

    getParameter(String name);通过表单提交的name属性名称获取对应的值。

    setCharacterEncoding(String charset);设置POST请求的编码格式,因为默认是使用ISO-8859-1接收数据。

    注意:GET方法在tomcat8.0后默认使用UTF-8编码,如果是8.0之前还是需要转码,如果不是使用 tomcat服务器,根据具体情况确定是否需要转码。

    @WebServlet("/login.do") public class LoginServlet extends HttpServlet{ @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("正在接收数据:"); String username = request.getParameter("username"); //接收表单name为username的数据 // GET方式的转码 // Tomcat8.0以后默认设置本来就是UTF-8,不需要转码,所以一般针对8.0之前的版本 // username = new String(username.getBytes("ISO-8859-1"), "UTF-8"); System.out.println(username); } @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("正在接收数据:"); request.setCharacterEncoding("utf-8"); // 转码 String username = request.getParameter("username"); //接收表单name为username的数据 System.out.println(username); } }

    index.html

    注意:此处action属性中的路径应该写login.do而不能写/login.do,前面有/表示绝对路径,需要加上工程名称,正确的写法应该是/day11/login.do,但是并不能保证工程名称一定叫day11,所以应该使用动态方式(后面讲解)。

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"/> <title>Title</title> </head> <body> <form method="get" action="login.do"> <input type="text" name="username" placeholder="用户名"/> <input type="submit" value="提交"/> </form> </body> </html>
    5.2 response的使用

    response用来封装服务器对客户端的响应。通常会输出html页面内容。

    常见的方法有两个:

    getWriter():得到向页面输出的输出对象。

    setContentType(String type):设置响应的内容类型和文本字符集。

    @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("正在接收数据:"); request.setCharacterEncoding("utf-8"); // 转码 String username = request.getParameter("username"); //接收表单name为username的数据 // 设置响应的类型和字符集 response.setContentType("text/html;charset=utf-8"); // 得到向页面响应输出的对象 PrintWriter out = response.getWriter(); out.println("<!DOCTYPE html>"); out.println("<html>"); out.println("<head>"); out.println("<meta charset=\"UTF-8\"/>"); out.println("</head>"); out.println("<body>"); out.println("<h1>当前用户为:"+username+"</h1>"); out.println("</body>"); out.println("</html>"); }

    六、重定向和请求转发【重点】

    6.1 重定向

    在servlet中需要跳转到其他的页面或者servlet中,可以使用重定向方式。

    该方式特点如下:

    地址栏地址会变化。至少有两次请求。多次请求直接request对象不会共享,所以不会共享request对象中的数据。可以跳转到站外。 @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("正在接收数据:"); request.setCharacterEncoding("utf-8"); // 转码 String username = request.getParameter("username"); //接收表单name为username的数据 String password = request.getParameter("password"); // 登录的逻辑 if (username.equals("zhangsan")&&password.equals("123456")){ // 登录成功 // 重定向到成功servlet(相当于页面上的<a>标签被点击) response.sendRedirect("success.html"); }else{ // 登录失败 response.sendRedirect("fail.html"); } }
    6.2 请求转发

    在servlet中需要跳转到其他的页面或者servlet中,可以使用请求转发方式。

    该方式特点如下:

    属于服务器的行为。只是一次请求。地址栏地址不会发生改变。请求对象会进行多次传递,所以可以使用request对象共享数据。不能转发给站外。可以手动存储数据以传递下一个servlet或页面。

    注意:手动存储数据使用setAttribute(String key, Object obj);获取数据使用getAttribute(String key);返回Object类型,需要强制转换类型。

    getAttribute(String key)和getParameter(String name)区别:

    attribute是程序手动存储数据。所以有setAttribute方法和getAttribute方法。

    parameter是容器封装请求对象时存储的数据,所以只有getParameter()方法。

    @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("正在接收数据:"); request.setCharacterEncoding("utf-8"); // 转码 String username = request.getParameter("username"); //接收表单name为username的数据 String password = request.getParameter("password"); // 登录的逻辑 if (username.equals("zhangsan")&&password.equals("123456")){ // 登录成功 // 请求转发(将当前servlet的request和response对象传递下一个页面或者servlet) // 获得当前用户的余额(通常是查询数据库得到) String money = "3000元宝"; // 将信息存入到request对象中,以键值对的形式 request.setAttribute("money", money); request.getRequestDispatcher("success.html").forward(request, response); }else{ // 登录失败 response.sendRedirect("fail.html"); } }

    七、综合案例

    见day11_demo

    八、Servlet生命周期

    Servlet生命周期是指Servlet对象从创建到销毁的过程以及过程中所经历的内容。

    创建(实例化new)-> 初始化(init) -> 服务(service)-> 销毁(destroy)

    注意:初始化只会调用一次。服务是指Servlet接口中的方法。destroy方法是指在将要销毁之前调用的方法,一般用来释放资源等。

    九、Servlet线程安全问题

    Servlet是单实例,多线程。

    要解决线程安全问题,一般有以下方案:

    实现SingleThreadModel接口,使Servlet在访问时变为单线程,那么必然安全,但是性能太低,不推荐。

    使用Synchronized代码块。

    使用技巧:尽量能不能使用全局变量就不要使用(推荐使用局部变量),或者仅使用只读的全局变量。从源头断绝线程安全问题出现。

    十、状态管理

    HTTP协议是无状态的,即服务器不会记录客户端的信息。每一次发送请求和响应都不会记录相关的客户端状态,因为这样可以提升访问速度。

    如果需要进行状态管理,可以采用cookie或者session来处理。

    cookie是指在客户端记录与服务器的交互信息,下一次再访问服务器,服务器会读取cookie中信息。cookie是一个txt文本,不安全。

    session是指服务器会生成一个唯一的标识(sessionID),并将此表示发送到客户端,客户端会将其记录,下一次访问时服务器会访问此记录来确认是否访问过。相对安全。

    10.1 编码和解码

    cookie中不能保存中文,可以通过java.net.URLEncoder进行编码。然后使用java.net.URLDecoder中的decoder方法进行解码。

    例如:张三,编码后会变成张三,解码后又变成张三

    public static void main(String[] args) throws Exception{ String name = "张三"; System.out.println("原来名称:" + name); String encodeString = URLEncoder.encode(name, "utf-8"); System.out.println("编码后:" + encodeString); String decodeString = URLDecoder.decode(encodeString, "utf-8"); System.out.println("解码后:" + decodeString); }
    10.2cookie的使用

    首先,进入到IndexServlet来判断用户是否曾经登录并写入了cookie信息,如果没有则跳转到登录界面,如果写入了则跳转到首页。

    @WebServlet("/index.html") public class IndexServlet extends HttpServlet{ @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 以发会员卡案例为示例 // 获取用户请求中的cookies对象(让用户出示会员卡) Cookie[] cookies = request.getCookies(); // 没有找到响应的cookies对象(用户告知没有会员卡) if (cookies == null){ // 去登录,登录后保存cookie信息(去办理会员卡) response.sendRedirect("login.html"); }else{ // 找到一些cookies信息(用户出示了一堆会员卡《五花八门》) String value = null; // 循环查找有没有正确的cookie信息(将用户出示的一堆会员卡进行翻找,看是否有我们下发的会员卡) for (Cookie cookie : cookies) { // 如果找到了对应的cookie信息(找到了我们下发的会员卡) if (cookie.getName().equals("day12_username")){ value = cookie.getValue(); // 记录该cookie信息(记录该会员卡信息) break; // 跳出循环(不再翻找剩下的会员卡) } } // 如果最终没有记录正确的cookie信息,说明没有登录过(如果没有找到我们下发的会员卡) if (value == null){ // 去登录,登录后保存cookie信息(去办理会员卡) response.sendRedirect("login.html"); }else{ // 如果找到了cookie信息,就跳转到首页并显示对应的信息(如果找到了会员卡,就允许直接进) request.setAttribute("currentUser", value); // 保存信息 request.getRequestDispatcher("home.html").forward(request, response); } } } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req, resp); } }

    登录时,如果登录成功需要将用户信息写入到cookie。

    @WebServlet("/login.do") public class LoginServlet extends HttpServlet{ @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 接收用户登录信息 String name = request.getParameter("name");// 用户名 String password = request.getParameter("password");// 密码 if (name.equals("zhangsan") && password.equals("123456")){ // 登录成功 // 将登录成功的用户信息保存到cookie中 Cookie cookie = new Cookie("day12_username", name); // 创建对象(注意不要中文) cookie.setPath("/day12"); //设置路径 cookie.setMaxAge(60*60*12); // 设置生命周期,单位是秒,此处设置12小时 response.addCookie(cookie); // 将cookie写入到响应对象中 request.setAttribute("currentUser", name); // 保存信息 request.getRequestDispatcher("home.html").forward(request, response); }else{ response.sendRedirect("fail.html"); } } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req, resp); } }

    cookie的优点:可以设置到期规则,相对简单。

    cookie的缺点:不安全;数据大小有限制,一般默认大小不能超过4kb;容易被安全工具禁用了浏览器的cookie。

    #####10.3 session的使用

    session一般指一次会话。(一个浏览器与服务器之间的多次请求和响应的过程叫一次会话)

    session的原理:由于cookie解决HTTP无状态问题时,会有三个缺点。通过session能够解决这三个问题。

    使用session,会将数据保存在服务器,大小能够超出4kb的cookie的范围;将sessionID发送到客户端保存在cookie中,安全问题大大减低;即使浏览器禁用了cookie,也能够通过url重写(将sessionid以参数?的形式传递到服务器)的办法来解决。

    session作为一个作用域,也具备setAttribute,getAttribute,removeAttribute三个常规操作方法。有效范围是一个会话范围。

    会话的注销(销毁)的方法是session.invalidate();

    LoginController

    @WebServlet("/login.do") public class LoginController extends HttpServlet{ @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 接收用户参数 String username = request.getParameter("username"); String password = request.getParameter("password"); if (username.equals("zhangsan") && password.equals("123456")){ // 登录成功 HttpSession session = request.getSession(); // 获取当前session对象(类似于map) System.out.println("JSESSIONID=====" + session.getId());// 输出sessionID session.setAttribute("user", username); // 将登录成功的用户信息存入到session中 response.sendRedirect("home.html"); }else { // 登录失败 response.sendRedirect("fail.html"); } } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req, resp); } }

    LogoutController

    @WebServlet("/logout.do") public class LogoutController extends HttpServlet{ @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { request.getSession().invalidate(); // 注销当前用户 response.sendRedirect("index.html"); // 跳转到登录界面 } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req, resp); } }

    HomeJSP.java

    @WebServlet("/home.html") public class HomeJSP extends HttpServlet{ @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // 判断用户是否登录,如果没有登录,则跳转到登录页面 HttpSession session = request.getSession(); // 得到session String user = (String)session.getAttribute("user"); // 得到user信息 // 如果没有得到信息,则未登录 if (user == null){ // 跳转登录页面 response.sendRedirect("index.html"); }else{ response.setContentType("text/html;charset=utf-8"); PrintWriter out = response.getWriter(); out.println("<h1>欢迎你,"+user+"</h1>"); out.println("<a href=\"first.html\">First</a>"); out.println("<a href=\"second.html\">Second</a>"); out.println("<a href=\"logout.do\">注销</a>"); } } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doGet(req, resp); } }
    10.4 ServletContext

    ServletContext指Servlet上下文,通常是指一个服务器(容器)对应的上下文。

    作为一个作用域,范围是全局范围,即所有的用户皆可访问。

    与前面学习的作用域比较范围大小如下:ServletContext > HttpSession > HttpServletRequest > PageContext

    常见的方法:

    getContextPath()得到上下文的名称,即工程的名称。

    getRealPath("/")得到项目实际的完整路径。

    十一、过滤器

    过滤器是指在客户端与请求资源之间建立的一个拦截组件。它能够拦截用户的请求,并对请求进行一定的过滤分析,如果满足需求则放行,否则会被拦截并要求转向。

    11.1 创建和配置

    需要实现一个Filter接口。并将过滤逻辑写在doFilter方法中。

    注意:doFiter方法中最后一定应该有过滤器链处理的代码。

    @WebFilter("/*") // 配置过滤的路径 public class MyFilter implements Filter{ @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { System.out.println("过滤器开始过滤..."); HttpServletRequest request = (HttpServletRequest) servletRequest; HttpServletResponse response = (HttpServletResponse) servletResponse; // 简单逻辑 System.out.println("uri===" + request.getRequestURI()); System.out.println("url===" + request.getRequestURL()); String url = request.getRequestURI(); // 得到请求的路径 // 判断请求路径是否合法 if (url.endsWith("/first.do") || url.endsWith("/first.html") || url.endsWith("/index.html") || url.endsWith("/") ) { // 什么都不做(放行) }else{ // 跳转到index页面 response.sendRedirect("index.html"); System.out.println("hello, world"); return; } // 放过请求 filterChain.doFilter(servletRequest, servletResponse); // 让过滤器链继续执行下一步过滤 } @Override public void destroy() { } }

    Filter的配置一般有两种方式:

    1.使用web.xml中配置

    2.使用@WebFilter()注解配置

    web.xml配置

    <filter> <filter-name>myFilter</filter-name> <filter-class>com.qf.day13.utils.MyFilter</filter-class> </filter> <filter-mapping> <filter-name>myFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>

    注解配置见上面的案例代码

    11.2 过滤器链

    过滤器链是指在项目如果存在多个过滤器,则构成过滤器链,当发送请求时会依次通过过滤器链上的所有过滤的过滤。

    当某一个过滤器禁止了请求的继续过滤时,一定要该代码后加上return。否则会引发Cannot call sendError…异常。

    过滤器链优先级:

    如果都在web.xml中配置,则按照配置的filter-mapping的顺序。

    如果都使用注解配置,则按照类名称的字母顺序。

    如果既有web.xml配置也有注解配置,web.xml配置的优先。

    11.3 过滤器实际应用

    在项目中过滤器一般应用在转码、认证、权限等场景。

    下面代码演示了转码和认证的场景:

    转码过滤器

    @WebFilter("/*") public class CharacterEncodingFilter implements Filter{ @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { System.out.println("开始转码..."); servletRequest.setCharacterEncoding("utf-8"); // POST转码 filterChain.doFilter(servletRequest, servletResponse); // 让过滤器链继续执行过滤 } @Override public void destroy() { } }

    认证过滤器

    @WebFilter("/*") public class AuthFilter implements Filter{ @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { System.out.println("AuthFilter开始过滤..."); HttpServletRequest request = (HttpServletRequest) servletRequest; HttpServletResponse response = (HttpServletResponse) servletResponse; String uri = request.getRequestURI(); // 得到请求的路径 if (uri.endsWith("/login.do") || uri.endsWith("/index.html")|| uri.endsWith("/fail.html")){ // url放行 }else{ HttpSession session = request.getSession(); String user = (String) session.getAttribute("user"); if (user == null){ response.sendRedirect("index.html"); return; } } filterChain.doFilter(request, response); } @Override public void destroy() { } } 关于过滤器的想法和总结: 因为过滤器起到拦截和放行的作用,所以在跳转时需要慎重,因为通过getURI获取的路径是request 携带的目标地址,过滤器是横在浏览器和目标地址之间的拦路虎,你需要符合你所写的过滤逻辑,搞清楚怎么样可以放过,怎么样会被拦截,发送到其他的界面。
    Processed: 0.013, SQL: 9