JSP&Web组件Filter

JSP

当浏览器请求访问.jsp资源时,tomcat会把这个请求交给JspServlet来处理的。如下web.xml文件所示

<servlet>
        <servlet-name>jsp</servlet-name>
        <servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
        <init-param>
            <param-name>fork</param-name>
            <param-value>false</param-value>
        </init-param>
        <init-param>
            <param-name>xpoweredBy</param-name>
            <param-value>false</param-value>
        </init-param>
        <load-on-startup>3</load-on-startup>
    </servlet> 
<servlet-mapping>
        <servlet-name>jsp</servlet-name>
        <url-pattern>*.jsp</url-pattern>
        <url-pattern>*.jspx</url-pattern>
    </servlet-mapping>

该Servlet把jsp页面翻译成java文件(jsp语法翻译成java代码,html代码则原封不动),被翻译成的java文件本质上是一个servlet。所以.jsp本质上也是一个servlet。

为什么会有jsp

虽然jsp的本质是一个servlet,但是纯正的servlet写html代码不太合适,比较适合写逻辑处理。而jsp被用做页面显示则比较合适。

JSP语法

JSP表达式

<%= 变量或者表达式 %> —翻译—> out.write(变量或表达式) —>(resp.getWriter().println())

JSP脚本片段

里面的内容会原封不动地输出到service方法内。

<%
  System.out.println("hello jsp");   ---------------->   System.out.println("hello jsp");
%>

或:
脚本片段每一个片段可以不用符合java语法,但是只要最终拼接的结果符合java语法就可以

<%
  for (int i = 0; i < 10; i++) {  
%>
  <h1>hello h1</h1>
<%
  }
%>

JSP声明

<%!
  //翻译到service方法外面
  private String name = "zhangsan";      --------------->  //翻译到service方法外面
    														private String name = "zhangsan";
%>

JSP九大对象

request
response
pageContext
session
exception
application
config
out
page
都可以直接在jsp和jsp脚本片段中使用

PageContext

在jsp中最为重要的一个对象,因为通过pageContext对象可以得到其他八个对象
1.pageContext本身也是一个域,范围是当前页面内有效
2.可以给其他域赋值

1.pageContext可以获取其他八个对象 2.第三个参数是1,2,3,4

pageContext.setAttribute("name","request",PageContext.REQUEST_SCOPE);
pageContext.setAttribute("name","session",PageContext.SESSION_SCOPE);
pageContext.setAttribute("name","application",PageContext.APPLICATION_SCOPE);
<%=request.getAttribute("name")%>
<%=session.getAttribute("name")%>
<%=application.getAttribute("name")%>

3.还有一个findAttribute方法

该API在查找数据的时候,依次按照从pageContext < request <session <application查找,找到则结束,找不到则到下一个域去查找,全部都查找不到,则返回null。

out
<%="hello out"%>
<%
    response.getWriter().println("hello response");
%>

最终页面的显示结果是hello response在前面 hello out在后面,为什么会出现这种情况呢?

如果想按照书写的先后顺序输出:可以关闭out对象的缓冲区

<%@ page contentType="text/html;charset=UTF-8" buffer="none" language="java" %>

Web组件

Servlet

Listener

监听器。ServletContext对象创建和销毁,会执行对应的动作。Spring初始化场所

使用Listener

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;

@WebListener   //注册,加载到内存中
public class MyServletContextListener implements ServletContextListener { //编写类实现相应接口
    @Override
    public void contextInitialized(ServletContextEvent servletContextEvent) {
        System.out.println("context init");
    }

    @Override
    public void contextDestroyed(ServletContextEvent servletContextEvent) {
        System.out.println("context destroy");
    }
}

Filter

过滤器

编写Filter

  1. 编写一个类实现Filter接口
  2. 声明该Filter
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
@WebFilter("/filter")
public class FitstFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("init");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("doFilter");
    }

    @Override
    public void destroy() {
        System.out.println("destroy");
    }
}

Filter生命周期

init:应用被加载就会执行初始化
doFilter:每一次访问到filter,都会执行
destroy:应用被卸载或者服务器关闭

Filter与Servlet产生关联

设置相同的url-pattern,设置完成后,filter默认拦截该servlet。但设置一行代码后,可以放行。
Filter的url-pattern可以设置为" / "。来匹配更多的servlet*

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
@WebFilter("/servlet1")
public class FitstFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("init");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        System.out.println("doFilter");
        //有这行代码表示请求放行
        filterChain.doFilter(servletRequest,servletResponse);
    }

    @Override
    public void destroy() {
        System.out.println("destroy");
    }
}

Filter中doFilter()代码执行顺序

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
@WebFilter("/*")
public class FitstFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("init");
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        servletRequest.setCharacterEncoding("utf-8");
        System.out.println("doFilter before");
        //不可以设置在doFilter下面,如果放下面则该行代码会在servlet代码执行完毕之后再执行
        servletResponse.setContentType("text/html;charset=utf-8");
        //有这行代码表示请求放行
        //代码执行到这一行,会跳转到下一个组件(下一个Filter或者servlet)
        filterChain.doFilter(servletRequest,servletResponse);
        System.out.println("doFilter after");
    }
    @Override
    public void destroy() {
        System.out.println("destroy");
    }
}

执行顺序为:

doFilter before
执行Servlet内容
doFilter after

代码执行到doFilter行时,请求会分发给下一个组件执行,执行完毕之后才返回回来。

多个Filter共享一个url-pattern以及注意事项

多个filter可以设置相同的url-pattern。
调用顺序:

  1. 对于通过注解定义的filter来说,先后顺序取决于类名首字母的ASCII先后顺序。
  2. 对于在web.xml定义的filter来说,先后顺序取决于filter-mapping节点声明的先后顺序

一个请求的完整流程

1.地址栏输入http://localhost:8080/app/servlet,浏览器构建请求报文,发送出去

2.中转传输到服务端,被监听8080端口的connector接收,将其解析成request对象和response对象

3.传给engine,engine挑选host,默认有一个host localhost,如果没有找到其他可匹配的host,也会交给该host来处理

4.host选择Context,寻找一个叫做app的context

5.将这两个对象传给app这个Context

6.根据你的请求地址/servlet,在当前应用内查找有没有对应的filter可以处理该请求,将可以处理的filter组件加入到链表中,如果有多个,那么就按照刚刚所说的先后顺序进行放置

7.再查找有没有对应的servlet可以处理该请求,如果有的话,则将该servlet也加入到链表中;如果没有,会将缺省servlet加入到链表中

8.将request和response对象依次传给链表中的每个组件,filter的话就调用filter的doFilter方法,servlet的话,就调用servlet的service方法

9.执行完毕,当前Context处理过程结束,将request和response依次返回,返回给connector

10.connector读取response里面的数据,然后做出响应

Filter的url-pattern表现特异性

和servlet有两点很不一样。

servlet的url-pattern是不允许设置多个servlet配置同一个,但是filter没有这个限制

servlet的url-pattern不建议设置/*,但是filter没有这个限制

分析:从功能角度去分析。

在创造出这两个组件的时候,赋予他们的功能上的一个不同,差异。

servlet是用来开发动态web资源的,做出响应的,如果可以设置多个servlet映射同一个url-pattern,那么就会出现很多问题。

但是对于filter来说,没有这个问题,因为filter设计之初它的功能就是用来进行拦截,过滤,不作出响应。

分析他们这点的差异的话,尽量从功能上去理解,简单理解为就是这么规定的。

Filter功能

设置编码格式、权限验证、部分页面拦截、部分页面放行

package test2;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Set;

@WebFilter("/*")  // 匹配所有的servlet
public class Filter implements javax.servlet.Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        servletRequest.setCharacterEncoding("utf-8");  //修改解析请求报文的字符集。tomcat默认是ISO-8859-1,设置成与浏览器页面相同的utf-8
        servletResponse.setContentType("text/html;charset=utf-8");  
        if(isBlack(servletRequest)) {
           servletResponse.getWriter().println("你谁啊你!");
           return;
       } else {
            filterChain.doFilter(servletRequest,servletResponse);  //若不在黑名单中,则放行
        }
    }

    private boolean isBlack(ServletRequest req) {
        Set<String> set = (Set<String>)req.getServletContext().getAttribute("black");
        if(set.contains(req.getRemoteAddr())) {
            return true;
        }
        return false;
    }

    @Override
    public void destroy() {

    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值