zoukankan      html  css  js  c++  java
  • Servlet & JSP & Filter & Listener

    Servlet & JSP & Filter & Listener

    graph TB B[Servlet] C[JSP] B --> D[基本原理与执行流程<br>init/service/do.] B --> H[service&反射] B --> I[单例] C --> E[隐式对象] C --> F[JSTL&EL] C --> G[session<br>JavaBean]

    Servlet

    Servlet 是运行在服务器端的一个对象,web 服务器(如 Tomcat)会根据用户的访问链接将请求路由到不同的 Servlet 中并由其处理与返回响应。路由配置一般在 web.xml 中,当然也可以使用注解的形式。

    特点

    • 单例
    • Servlet 在请求时实例化与初始化,web 服务创建时默认不创建 Servlet 对象,不过可以配置自启动(load-on-startup

    基本原理

    下面是 HTML & servlet & web.xml 的一个示例

    HTML(注意 action 和 method 的取值):

    ...
    <form action="login" method="post">
    账号: <input type="text" name="name"> <br>
    密码: <input type="password" name="password"> <br>
    <input type="submit" value="登录">
    </form>
    ...
    

    web.xml(注意 Servlet 和 url 路径的映射关系):

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app>
        <servlet>
            <servlet-name>LoginServlet</servlet-name>
            <servlet-class>LoginServlet</servlet-class>
            <load-on-startup>10</load-on-startup> 
        </servlet>
        <servlet-mapping>
            <servlet-name>LoginServlet</servlet-name>
            <url-pattern>/login</url-pattern>
        </servlet-mapping>  
    </web-app>
    

    Servlet:

    public class LoginServlet extends HttpServlet{
        // @Override // 当前函数的作用见下
        // public void service(HttpServletRequest request, HttpServletResponse response){...}
        // public void init(ServletConfig config) {...} // 继承于父类,Servlet 的构造函数执行后会自动执行此函数,只会执行一次
     	// 处理 GET 请求
        public void doGet(HttpServletRequest request, HttpServletResponse response){
            try {
                response.getWriter().println("<h1>Hello Servlet!</h1>");
                response.getWriter().println(new Date().toLocaleString());
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        // 处理 POST 请求
        public void doPost(HttpServletRequest request, HttpServletResponse response){
            try{
                String name = request.getParameter("name");
            	String password = request.getParameter("password");
            }catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    

    每一个 Servlet 都需要继承 HttpServlet。HttpServlet 中有一个 service 成员函数,默认的 service 会判断请求中的方法,并根据方法(GET or POST)来调用当前函数下的 doGet 或者 doPost 方法。结合 Filter(见下文) & 重写service & 反射可以实现一个 servlet 处理不同的请求,如下所示:

    使用 Filter 拆分用户的请求,下面代码截取自一段 Filter 对象:

    // 假设请求的方法是 ***/admin_category_list
    if(uri.startsWith("/admin_")){		
    	String servletPath = StringUtils.substringBetween(uri,"_", "_") + "Servlet"; // 确定 Servlet
    	String method = StringUtils.substringAfterLast(uri,"_" );
    	request.setAttribute("method", method); // 确定方法
    	req.getRequestDispatcher("/" + servletPath).forward(request, response); // 执行 Servlet
    	return;
    }
    

    重写 service 函数并使用反射选择与执行 Servlet 中的方法(此时 Servlet 中可以没有 doGet 和 doPost):

    @Override
    public void service(HttpServletRequest request, HttpServletResponse response) {
        ...
        try {
            /*借助反射,调用对应的方法*/
            String method = (String) request.getAttribute("method");
            Method m = this.getClass().getMethod(method, javax.servlet.http.HttpServletRequest.class,
                                                 javax.servlet.http.HttpServletResponse.class,Page.class);
            String redirect = m.invoke(this,request, response,page).toString();
        }
        ...
    }
    

    常见方法

    • 跳转
      • 服务端跳转(返回跳转页的响应内容但不改变浏览器地址):request.getRequestDispatcher("success.html").forward(request, response);
      • 客户端跳转(服务端向客户端发送重定向地址):response.sendRedirect("fail.html");
    • Servlet 自启动
      • 在 web.xml 中配置 <load-on-startup>10</load-on-startup> ,可以实现 Servlet 的自启动

    JSP

    JSP(Java Server Pages),一个混合 Java&HTML 的网页编写技术。JSP 最终将会被翻译为 Servlet 。JSP 继承于 HttpJspBase,而后者继承自 HttpServlet。

    JSP 示例

    <%@ page language="java" contentType="text/html; charset=UTF-8"
        pageEncoding="UTF-8" import="java.util.*"%>
    <%
        List<String> words = new ArrayList<String>();
        words.add("today");
        words.add("is");
        words.add("great");
    %>
    <table width="200px" align="center" border="1" cellspacing="0">
    <%for (String word : words) {%>
    <tr>
        <td><%=word%></td>
    </tr>
    <%}%>
    </table>
    

    网页中输出如下:

    today
    is
    great

    JSP 组成

    JSP 由这些页面元素组成:

    1. 静态内容,html、css、javascript 等内容
    2. 指令,以<%@开始 %> 结尾,比如 <%@page import="java.util.*"%>
    3. 表达式 <%=%>,用于输出一段html,<%="hello jsp"%> 类似于 <%out.println("hello jsp");%>
    4. Scriptlet,在 <%%> 之间,可以写任何 java 代码
    5. 声明,在<%!%> 之间可以声明字段或者方法。但是不建议这么做。
    6. 动作,<jsp:include page="Filename" >jsp 页面中包含另一个页面。
    7. 注释 <%-- -- %>,不同于 html 的注释<!-- --> 通过 jsp 的注释,浏览器也看不到相应的代码,相当于在servlet中注释掉了

    隐式对象

    不需要显式定义就可以使用的对象。JSP 一共有 9 个隐式对象,分别为:

    • request、response、out,out 为输出
    • pageContext、session、application,分别代表当前页,会话,全局作用域对象
    • JSP 会被编译为一个 Servlet 类 ,运行的时候是一个 Servlet 实例。 page 即代表 this
    • config,config 可以获取一些在 web.xml 中初始化的参数
    • exception,异常对象,指定的异常处理页面才可使用

    JSTL

    JSTL(JSP Standard Tag Library),JSTL允许开人员可以像使用 HTML 标签那样在 JSP 中开发 Java 功能。

    常见函数标签:fmt、fn

    <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%
    <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%> <%-- 指明后续的标签使用都会以<c: 开头 --%>
    
    <c:set var="name" value="${'gareen'}" scope="request" />
    通过标签获取name: <c:out value="${name}" /> <br> <%-- 类似<%=request.getAttribute("name")%> --%>
    
    <c:remove var="name" scope="request" /> <br>
    通过标签获取name: <c:out value="${name}" /> <br>
    
    <c:set var="hp" value="${3}" scope="request" /> <%-- 循环示例 --%>
    <c:choose>
        <c:when test="${hp<5}">
            <p>这个英雄要挂了</p>
        </c:when>
        <c:otherwise>
            <p>这个英雄觉得自己还可以再抢救抢救</p>
        </c:otherwise>
    </c:choose>
    

    EL 表达式

    EL表达式可以从 pageContext、request、session、application四个作用域中取到值,如果 4 个作用域都有相同属性,EL会按照从高到低的优先级顺序获取:pageContext > request > session > application

    JSP 常见用法

    • include
      • 指令 include:<%@include file="footer.jsp" %>,当前 JSP 将插入到命令行位置
      • 动作 include:<jsp:include page="footer.jsp" />,footer.jsp 会被转化未 footer_jsp.java 以 Servlet 的形式存在,footer_jsp.java 的执行结果会插入到命令位置
    • 跳转
      • 客户端跳转:<%response.sendRedirect("hello.jsp");%>
      • 服务端跳转:<jsp:forward page = "hello.jsp"/>

    JavaBean

    JavaBean 的标准

    1. 提供无参 public 的构造方法(默认提供)
    2. 每个属性,都有 public 的 getter 和 setter
    3. 如果属性是 boolean,那么就对应 is 和 setter 方法

    Session

    Session 就是是会话。会话指的是从用户打开浏览器访问一个网站开始,无论在这个网站中访问了多少页面,点击了多少链接,都属于同一个会话,直到该用户关闭浏览器为止。

    Servlet + JSP ≈ MVC

    Servlet 方便写 Java 代码,JSP 方便写页面代码,结合二者的特点,使用 Servlet 写业务相关代码,使用 JSP 进行展示。

    Servlet,将数据保存到隐式对象

    public class HeroEditServlet extends HttpServlet {
     
        protected void service(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
            int id = Integer.parseInt(request.getParameter("id"));
            Hero hero = new HeroDAO().get(id);
            request.setAttribute("hero", hero); // 设置属性后 JSP 使用 EL 语言 ${hero.id},获得数据
            request.getRequestDispatcher("editHero.jsp").forward(request, response);
        }
    }
    

    JSP,从隐式对象中获得数据

    <form action='updateHero' method='post'>
        名字 : <input type='text' name='name' value='${hero.name}'> <br>
        血量 :<input type='text' name='hp' value='${hero.hp}'> <br>
        伤害: <input type='text' name='damage' value='${hero.damage}'> <br>
        <input type='hidden' name='id' value='${hero.id}'>
        <input type='submit' value='更新'>
    </form>
    

    应用举例

    • 使用分页技术显示部分数据
      • 后台返回在指定范围内的数据,前端显示

    Filter

    Filter 就像一个一个哨卡,用户的请求需要经过 Filter,可以设置多个 Filter

    graph LR A[用户访问] A --> B((Filter 1)) B --> C((Filter 2)) C --> D((Filter ..)) D --> E[Servlet]

    示例

    web.xml 配置

    <filter>
        <filter-name>FirstFilter</filter-name>
        <filter-class>filter.FirstFilter</filter-class>
    </filter>
     
    <filter-mapping>
        <filter-name>FirstFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    

    Filter

    public class FirstFilter implements Filter {
        @Override
        public void destroy() { }
     
        @Override
        public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
                throws IOException, ServletException {
            HttpServletRequest request = (HttpServletRequest) req;
            HttpServletResponse response = (HttpServletResponse) res;
     		...
            chain.doFilter(request, response);
        }
     
        @Override
        public void init(FilterConfig arg0) throws ServletException {
     	// Filter一定会随着 tomcat 的启动自启动,故 init 随着 tomcat 启动时执行
        }
    }
    

    Listener

    Listener 用于监听 web 应用的创建与销毁、全局属性的变化、Session和Request对象的声明周期。

    继承 ServletContextListener 对象并实现其中两个方法的对象可以实现对 web 创建与销毁的监听,每当 web 应用重启或者销毁,系统会自动调用对应的函数。

    继承 ContextAttributeListener 并实现其中函数,可以在全局属性发生变化时(增、删、改等)执行指定函数。

    同样的,可以编写 Listener 实现 Session&Request 对象的生命周期和属性变化的监控。

    举个例子,通过记录 Session 的个数可以实现在线用户的计算。以一种简单的方式,通过编写 Listener 来监控 Session 的创建与销毁并在对应时刻修改全局计数器的值,这样就可以实现在线用户的统计了。可参考

  • 相关阅读:
    python print format
    ElasticSearch的lowlevelApi和低级别API
    Ubuntu下搜狗输入法突然无法输入中文
    mysql基本操作
    eclipse配置代码自动提示
    使用JAAS登录kerberos服务器
    centos7配置kerberos服务,并使用JAAS登录
    LDAP none、simple、strong 笔记
    linux下yum安装最新稳定版nginx
    Mybatis if标签判断大小
  • 原文地址:https://www.cnblogs.com/jiahu-Blog/p/11596259.html
Copyright © 2011-2022 走看看