【web基础】servlet进阶

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/LoveHYZH/article/details/79337641

1.过滤器

  • Servlet和JSP中的过滤器都是Java类,它们存在的目的如下:
    • 在请求访问后端资源时拦截它
    • 管理从服务器返回给客户端的响应
  • 常用的过滤器类型:
    • 认证过滤器
    • 数据压缩过滤器
    • 加密过滤器
    • 触发资源访问事件的过滤器
    • 图像转换过滤器
    • 登录和验证过滤器
    • MIME类型链过滤器
    • 令牌过滤器
    • 转换XML内容的XSL/T过滤器
      过滤器将会被插入进web.xml文件中,然后映射servlet、JSP文件的名字,或URL模式
      当JSP容器启动网络应用程序时,它会创建每一个过滤器的实例,这些过滤器必须在部署描述文件web.xml中声明,并且按声明的顺序执行。
  • Servlet过滤器方法
    一个过滤器就是一个Java类,它实现了javax.servlet.Filter 接口。
    javax.servlet.Filter接口定义了三个方法:
    • public void doFilter (ServletRequest, ServletResponse, FilterChain)
      每当 request/response要通过过滤链时容器会调用这个方法,因为客户端请求链尾的资源
    • public void init(FilterConfig filterConfig)
      容器调用这个方法来表明一个过滤器被安置在服务中
    • public void destroy()
      容器调用这个方法来表明一个过滤器正在从服务中移除
  • 过滤器示例
    类似servlet写法,这里只示例注解实现了
package com.huawei.filter;

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

@WebFilter(filterName = "FirstFilter", urlPatterns = "/*")
public class FirstFilter implements Filter {
    public void destroy() {
    }

    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
        System.out.println("Filter starts...");
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) resp;
        resp.setContentType("text/html;charset=utf-8");
        PrintWriter out = resp.getWriter();
        if(1!=1){
            out.println("IP is illegal");
        }else{
            out.println("Ip is 合法");
            chain.doFilter(req, resp);
        }
    }

    public void init(FilterConfig config) throws ServletException {
        System.out.print("初始化filter...");
    }
}
  • 多个过滤器应用顺序
    • 在web.xml中元素的映射顺序决定了容器应用这些过滤器的顺序。要反转应用的顺序,您只需要反转web.xml中元素的定义顺序就行了。

2.监听器

  • 什么是监听器
    servlet规范当中一个特殊的类,可以监听容器中产生的一些事件并做相应的处理。Listener 对应观察者模式,事件发生的时候会自动触发该事件对应的Listeer。Listener 主要用于对 Session、request、context 进行监控。
    8种监听器可以分为三类:
    • 第一大类:监听 Session、request、context 的创建与销毁
      HttpSessionLister、ServletContextListener、ServletRequestListener
    • 第二大类:监听对象属性变化
      HttpSessionAttributeLister、ServletContextAttributeListener、ServletRequestAttributeListener
    • 第三大类:监听Session 内的对象
      HttpSessionBindingListener、HttpSessionActivationListener
      与上面六类不同,这两类 Listener 监听的是Session 内的对象,而非 Session 本身,不需要在 web.xml中配置
  • 监听器加载顺序
    • 启动服务器->监听器->过滤器->servlet
    • Web服务器按照web.XML中注册顺序来加载Servlet事件监听器
    • Web应用程序中只会为每个事件监听器类创建一个实例对象,在编程中可能出现多个线程同时调用一个事件监听器的情况,要注意监听器对象共享同步问题。
  • 监听器的实现

这里写图片描述
这里写图片描述
这里写图片描述

<!--wweb.xml配置-->
<!--一般放在servlet之前-->
<listener>
    <listener-class>com.huawei.listener.FirstListener</listener-class>
</listener>

下面用注解方式写

package com.huawei.listener;

import javax.servlet.*;
import javax.servlet.annotation.WebListener;
import javax.servlet.http.*;

@WebListener()
public class FirstListener implements ServletContextListener,
        HttpSessionListener,ServletRequestListener {

    public FirstListener() {
    }

    //加载context
    public void contextInitialized(ServletContextEvent sce) {
        ServletContext servletContext = sce.getServletContext();
        System.out.println("即将启动"+servletContext.getContextPath());
    }

    //写在context
    public void contextDestroyed(ServletContextEvent sce) {
        ServletContext servletContext = sce.getServletContext();
        System.out.println("即将关闭"+servletContext.getContextPath());
    }

    //创建session
    public void sessionCreated(HttpSessionEvent se) {
        HttpSession session = se.getSession();
        System.out.println("新创建一个session"+session.getId());
    }

    //销毁session
    public void sessionDestroyed(HttpSessionEvent se) {
        HttpSession session = se.getSession();
        System.out.println("销毁一个session"+session.getId());
    }

    //创建request
    public void requestInitialized(ServletRequestEvent req){
        HttpServletRequest request = (HttpServletRequest) req.getServletRequest();
        String uri = request.getRequestURI();
        uri = request.getQueryString() == null ? uri : (uri + "?" + request.getQueryString());
        request.setAttribute("dateCreated", System.currentTimeMillis());
        System.out.println("IP " + request.getRemoteAddr() + " 请求 " + uri);
    }

    //销毁request
    public void requestDestroyed(ServletRequestEvent req){
        HttpServletRequest request = (HttpServletRequest) req.getServletRequest();
        long time = System.currentTimeMillis() - (Long) request.getAttribute("dateCreated");
        System.out.println(request.getRemoteAddr() + "请求处理结束, 用时" + time + "毫秒. ");
    }
}

3.AJAX

  • 什么是AJAX

    • AJAX = Asynchronous Javascript And Xml(异步的JavaScript和xml)
    • 是一种用于改善用户体验度的技术,实质上是利用浏览器内置对象 (XMLHttpRequest,一般称为ajax对象)向服务器发送异步请求,服务器接收到请求之后处理数据,处理完之后,返回结果,浏览器利用这结果数据部分更新页面,整个过程当中,页面无刷新,不会打断用户的操作。
    • AJAX对象在向服务器发送请求时,浏览器不会销毁当前页面,用户可以在页面中继续其他的操作
  • 创建XMLHttpRequest对象——ajax基础

<script>
    var xhr;
    if(window.XMLHttpRequest){
        xhr = new XMLHttpRequest();
    }else{
        xhr = new ActiveXObject("Microsoft.XMLHTTP");
    }
</script>
  • 原生js实现ajax
方法 描述
open(method,url,async) 规定请求的类型、URL 以及是否异步处理请求。
       ● method:请求的类型;
       ● GET 或 POST url:文件在服务器上的位置
       ● async:true(异步)或 false(同步)
setRequestHeader(header,value) 向请求添加 HTTP 头。
       ● header: 规定头的名称
       ● value: 规定头的值
send(string)
send()
将请求发送到服务器。
       ● string:仅用于POST请求

GET 还是 POST?

  • 与 POST 相比,GET 更简单也更快,并且在大部分情况下都能用。然而,在以下情况中,请使用 POST 请求:
    • 无法使用缓存文件(更新服务器上的文件或数据库)
    • 向服务器发送大量数据(POST 没有数据量限制)
    • 发送包含未知字符的用户输入时,POST 比 GET 更稳定也更可靠
  • 下面是 XMLHttpRequest 对象的三个重要的属性:
属性 描述
onreadystatechange 存储函数(或函数名),每当 readyState 属性改变时,就会调用该函数。
readyState

存有 XMLHttpRequest 的状态。从 0 到 4 发生变化。

  • 0: 请求未初始化
  • 1: 服务器连接已建立
  • 2: 请求已接收
  • 3: 请求处理中
  • 4: 请求已完成,且响应已就绪
status

200: "OK"

404: 未找到页面

  • 原生js写ajax
<script type="text/javascript">
    //get异步请求
    function change(v1){
        var xhr = getXhr();
        //添加随机数避免浏览器调用缓存不刷新
        xhr.open("get","tajax?t="+Math.random(),true);
        xhr.onreadystatechange = function(){
            if(xhr.readyState==4){
                var map = xhr.responseText;
                document.getElementById("div1").innerHTML = map;
            }
        }
        xhr.send();
    }
    //post异步请求
    function testajax() {
         var postData = {"name1":"value1","name2":"value2"};
         xhr.open("post","tajax",true);
         //这个就照着写吧0.0,设置http消息头
         xhr.setRequestHeader("Content-type","application/x-www-form-urlencoded");
         xhr.onreadystatechange = function () {
             if(xhr.readyState == 4){
                 var map = xhr.responseText;
                 document.getElementById("div1").innerHTML = map;
             }
         }
         xhr.send(postData);
     }
</script>
  • jQuery堆ajax的支持
$.ajax(options);
    options:是一些键值对{key:value,ke:value},其中的回调函数的入参也是可选的

    url:请求地址
    type:请求方式get/post
    data:请求参数
        "username=zs&age=10"
        {"username":"zs","age":10}
    dataType:服务器返回的数据类型
        html,text,xml,js,json等
    success:请求成功回调函数
        function(data,textStatus){
            data:服务器返回的数据
            textStaus:服务器返回的状态
        }
    error:请求失败回调函数  
        function(xhr,e){
            xhr:ajax对象
            e:服务器返回的状态
        }
$.ajax({
    "url":"loadCourse.do",
    "cache":false,
    "type":"post",
    "dataType":"json",
    "success":function(data){
            for(i=0;i<data.length;i++){
                var c = data[i];
                var $a = $("<a href='javascript:;' id='"+c.id+"'>"+c.courseName+"</a>");
                $a.click(clickCourse);
                $("#course").append($a);
                $("#course").append("&nbsp;");
            }
            $("#course").children('a').first().trigger('click');
    },
    "error":function(){
        alert("错误");
    }
});

4.servlet线程安全问题

  • servlet线程安全问题产生的原因
    在默认的情况下,容器只会为每一个servlet类创建唯一的一个实例,当请求到达容器时,就有可能有多个线程同时访问同一个实例。
  • 如何解决
    • 加锁(可以对整个service方法加锁,也可以对某一个代码块加锁。建议使用后者。)
    • 让servlet实现SingleThreadModle接口容器会为该servlet创建多个servlet对象,每启动一个线程为其分配一个servlet对象。
    • servlet属性尽量设置成可读的,不要去修改。final

猜你喜欢

转载自blog.csdn.net/LoveHYZH/article/details/79337641