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
- 编写一个类实现Filter接口
- 声明该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。
调用顺序:
- 对于通过注解定义的filter来说,先后顺序取决于类名首字母的ASCII先后顺序。
- 对于在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() {
}
}