• Servlet


    介绍

    Servlet是sun公司提供的一门用于开发动态web资源的技术。
    Servlet是JavaWeb的三大组件之一,它属于动态资源。Servlet的作用是处理请求,服务器会把接收到的请求交给Servlet来处理,在Servlet中通常需要:
    接收请求数据;

    【1.获取信息】
    处理请求;

    【2.调用方法】Dao中的方法

    完成响应
    【3.页面跳转】
      例如客户端发出登录请求,或者输出注册请求,这些请求都应该由Servlet来完成处理!Servlet需要我们自己来编写,每个Servlet必须实现javax.servlet.Servlet接口。

    使用

    Sun公司在其API中提供了一个servlet接口,用户若想要开发一个动态web资源(即开发一个Java程序向浏览器输出数据),需要完成以下2个步骤:

    1. 编写一个Java类,实现servlet接口。然后把开发好的Java类部署到web服务器中。

    public void doPost(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {
    //1.
    PrintWriter out = response.getWriter();//获取打印流对象
    out.println("hello_Servlet");//向浏览器打印数据
    out.flush();//刷新
    out.close();//关流
    }

     2.servlet需要进行注册(在web.xml中)(手动部署)

    <servlet>
            <servlet-name>Servlet1</servlet-name>
            <servlet-class>com.zym.servlet.Servlet1</servlet-class>
        </servlet>
    
        <servlet-mapping>
            <servlet-name> Servlet1</servlet-name>
            <url-pattern>/Servlet1</url-pattern>
        </servlet-mapping>

    还可以直接在生成的servlet文件中配置

    package com.zym.servlet;
    
    import javax.servlet.ServletConfig;
    import javax.servlet.ServletException;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    
    @WebServlet(name = "Servlet2",urlPatterns = "/Servlet2")
    public class Servlet2 extends HttpServlet {
    
    
        @Override
        public void init(ServletConfig config) throws ServletException {
            System.out.println("start.............");
        }
    
        protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    
        }
    
        protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    
        }
    }

    Servlet的编写及配置

    URL-Pattern的三种配置方式

    1、完全路径匹配 以/开始 不能包含统配符* 例如: /hello /init
    2、目录匹配 以/开始, /*结尾 例如: /* /aa/* /aaa/bbb/*
    3、扩展名匹配 不能以/开始,以*开始 例如: *.do *.action

    优先级

    优先级:完全匹配 > 目录匹配 > 扩展名匹配 

    example

    Servlet1 映射到 /abc/*
    Servlet2 映射到 /*
    Servlet3 映射到 /abc
    Servlet4 映射到 *.do
    当请求URL为“/abc/a.html”,“/abc/*”和“/*”都匹配,哪个servlet响应
        Servlet引擎将调用Servlet1。
    当请求URL为“/abc”时,“/abc/*”和“/abc”都匹配,哪个servlet响应
        Servlet引擎将调用Servlet3。
    当请求URL为“/abc/a.do”时,“/abc/*”和“*.do”都匹配,哪个servlet响应
        Servlet引擎将调用Servlet1。
    当请求URL为“/a.do”时,“/*”和“*.do”都匹配,哪个servlet响应
        Servlet引擎将调用Servlet2.
    当请求URL为“/xxx/yyy/a.do”时,“/*”和“*.do”都匹配,哪个servlet响应
        Servlet引擎将调用Servlet2。

    编写注意事项

    Servlet初始化时覆盖init() ,无需覆盖init(config)
    根据Http请求的方式,覆盖相应的doGet或者doPost方法,无需覆盖Service方法
    当doGet和doPost代码逻辑相同时,可以相互调用,简化编程

    Servlet的执行过程

    Servlet程序是由WEB服务器调用,web服务器收到客户端的Servlet访问请求后:
    Web服务器首先检查是否已经装载并创建了该Servlet的实例对象。
    装载并创建该Servlet的一个实例对象。
    调用Servlet实例对象的init()方法。
    创建一个用于封装HTTP请求消息的HttpServletRequest对象和一个代表HTTP响应消息的HttpServletResponse对象,然后调用Servlet的service()方法并将请求和响应对象作为参数传递进去。
    WEB应用程序被停止或重新启动之前,Servlet引擎将卸载Servlet,并在卸载之前调用Servlet的destroy()方法。

    Servlet线程安全

    当多个servlet的线程同时访问了servlet的共享数据,如成员变量,可能会引发线程安全问题。

    解决方法:

    1把使用到共享数据的代码块进行同步(使用synchronized关键字进行同步)

    2建议在servlet类中尽量不要使用成员变量。如果确实要使用成员,必须同步。而且尽量缩小同步代码块的范围。(哪里使用到了成员变量,就同步哪里!!),以避免因为同步而导致并发效率降低。

    ServletConfig对象和ServletContext对象(了解)

    ServletConfig

    在Servlet的配置文件中,可以使用一个或多个<init-param>标签为servlet配置一些初始化参数。

    当servlet配置了初始化参数后,通过ServletConfig对象得到初始化信息,web容器在创建servlet实例对象时,会自动将这些初始化参数封装到ServletConfig对象中,并在调用servlet的init方法时,将ServletConfig对象传递给servlet。进而,程序员通过ServletConfig对象就可以得到当前servlet的初始化参数信息。

    <servlet>
        <servlet-name>ConfigDemo</servlet-name>
        <servlet-class>gz.itcast.f_config.ConfigDemo</servlet-class>
        <!-- 初始参数: 这些参数会在加载web应用的时候,封装到ServletConfig   对象中 -->
        <init-param>
            <param-name>path</param-name>
            <param-value>e:/b.txt</param-value>
        </init-param>
      </servlet>
    
    在一个web应用可以存在多个ServletConfig对象(一个Servlet对应一个ServletConfig对象)
     在哪个servlet里面配置的初始化参数,只能在该servlet里面获取

    servletConfig对象获取

    ServletConfig config=this.getServletConfig(); 

    Servlet初始化参数

    //获取servletConfig对象
        ServletConfig config = this.getServletConfig();
    //得到初始化值
        String name = config.getInitParameter("name");
        String age = config.getInitParameter("age");
        String address = config.getInitParameter("address");
        System.out.println(name+"   "+age+"   "+address);

    ServletContext

    WEB容器在启动时,它会为每个WEB应用程序都创建一个对应的ServletContext对象,它代表当前web应用。
    ServletContext代表是一个web应用的环境(上下文)对象,ServletContext对象 内部封装是该web应用的信息,ServletContext对象一个web应用只有一个
    一个web项目只会有一个ServletContext对象
    ServletConfig对象中维护了ServletContext对象的引用,开发人员在编写servlet时,可以通过ServletConfig.getServletContext方法获得ServletContext对象。
    对象获取方法
    由于一个WEB应用中的所有Servlet共享同一个ServletContext对象,因此Servlet对象之间可以通过ServletContext对象来实现通讯。ServletContext对象通常也被称之为context域对象。

    了解ServletContext对象的功能

    web.xml中配置初始化参数
        <context - param>
        <param -name>driver</param - name>
        <param -value>com.mysql.jdbc.Driver</param - value>
        </context - param>
    通过context对象获得参数
        获取servletContext对象
        ServletContext context = getServletContext();
        获取初始化参数
        String initParameter = context.getInitParameter("driver");
        System.out.println(initParameter);

    context.getRealPath(“路径”) //得到web应用中的资源文件
    context.getResourceAsStream("路径");

     

    servletContext对象获取

    1)ServletContext servletContext = config.getServletContext();
    2)ServletContext servletContext = this.getServletContext();

    HttpServletRequest(重点)

    Request获取客户端请求信息

    getRequestURL方法返回客户端发出请求完整URL
    getRequestURI方法返回请求行中的资源名部分
    getQueryString 方法返回请求行中的参数部分
    getRemoteAddr方法返回发出请求的客户机的IP地址
    getMethod得到客户机请求方式
    getContextPath 获得工程虚拟目录名称

    Request获取请求头

    获得客户机请求头
        getHeader(name)方法 --- String 
        getHeaders(String name)方法 --- Enumeration<String>
        getHeaderNames方法 --- Enumeration<String>
    获得具体类型客户机请求头
        getIntHead(name)方法  --- int
        getDateHead(name)方法 --- long(日期对应毫秒)

    Request获取请求参数

    getParameter(name) --- String 通过name获得值
    getParameterValues  --- String[ ] 通过name获得多值 checkbox
    getParameterNames  --- Enumeration<String> 获得所有name
    getParameterMap  --- Map<String,String[ ]> key :name value: 多值

    Request请求参数乱码

    POST请求乱码 :request.setCharacterEncoding("utf-8"); 
    GET请求乱码 
        解决方案一:
            修改server.xml ,不建议使用此种解决方案
                <Connector port="80" protocol="HTTP/1.1" 
                           connectionTimeout="20000" 
                           redirectPort="8443" URIEncoding="utf-8"/>
        * 必须有修改tomcat服务器配置文件权限 
        解决方案二:逆向编解码
                      username = URLEncoder.encode(username, "ISO-8859-1");
                      username = URLDecoder.decode(username, "utf-8");
                      简化
                          username = new String(username.getBytes("ISO8859-1"),"utf-8");

    URL特殊字符转义规则

    常用转义规则
    空格换成加号(+) 
    +换成%2B 正斜杠(
    /)分隔目录和子目录 换成%2F 问号(?)分隔URL和查询 换成%3F 百分号(%)制定特殊字符 换成%25 #号指定书签 换成%23 &号分隔参数 换成%26 java.net.URLEncoder和 java.net.URLDecoder

    请求和重定向的区别

    RequestDispatcher.forward方法只能将请求转发给同一个WEB应用中的组件;而HttpServletResponse.sendRedirect 方法还可以重定向到同一个站点上的其他应用程序中的资源,甚至是使用绝对URL重定向到其他站点的资源。 
    如果传递给HttpServletResponse.sendRedirect 方法的相对URL以“/”开头,它是相对于服务器的根目录;如果创建RequestDispatcher对象时指定的相对URL以“/”开头,它是相对于当前WEB应用程序的根目录。 
    调用HttpServletResponse.sendRedirect方法重定向的访问过程结束后,浏览器地址栏中显示的URL会发生改变,由初始的URL地址变成重定向的目标URL;调用RequestDispatcher.forward 方法的请求转发过程结束后,浏览器地址栏保持初始的URL地址不变。
    HttpServletResponse.sendRedirect方法对浏览器的请求直接作出响应,响应的结果就是告诉浏览器去重新发出对另外一个URL的访问请求;RequestDispatcher.forward方法在服务器端内部将请求转发给另外一个资源,浏览器只知道发出了请求并得到了响应结果,并不知道在服务器程序内部发生了转发行为。 
    RequestDispatcher.forward方法的调用者与被调用者之间共享相同的request对象和response对象,它们属于同一个访问请求和响应过程;而HttpServletResponse.sendRedirect方法调用者与被调用者使用各自的request对象和response对象,它们属于两个独立的访问请求和响应过程。 

    HttpServletResponse (重点)

    Response设置响应头和状态码

    状态码(Status Code)
    setStatus(int)
    常用状态码:200、302、304、404、500

    头信息 (Header Info)
    addHeader(String,String) 在原有值添加
    setHeader(String,String) 替换原有值

    Response实现页面刷新

    //隔1秒之后,刷新到一个新页面
    resp.setHeader("Refresh", "1;/day02/a.html");
    //设置当前页面每隔1秒刷新一次
    resp.setHeader("Refresh", "1");

    Response实现重定向

    方案1:
        resp.setStatus(304);
        resp.setHeader("Location", "/FirstWeb/aa.jsp");
    方案2:
        resp.sendRedirect(“/FirstWeb/aa.jsp”); //推荐使用

    Response向页面输出内容

    response.getWriter().write();   发送字符实体内容
    response.getOutputStream().write()  发送字节实体内容
    字节流输出中文
        乱码和浏览器的编码有关
        设置浏览器默认打开的时候的编码集
        获得字节数组的时候,传入一个编码集
    字符流输出中文
        response的字符流的缓冲区是ISO-8859-1编码.
        设置response缓冲区的编码.
        设置浏览器的默认打开的时候字符集编码.

    Response开发细节

    向客户端输出字符中文的简写方式
    response.setContentType("text/html;charset=UTF-8");
    字节流与字符流是互斥的
    同一个页面只能使用一种流,不能同时向页面响应。
    使用字符流输入数字,有可能存在问题
    想输入数字时,使用字符串”1”

    Response实现文件下载

    设置头信息response.setHeader(“Content-Disposition”,” attachment;filename=”+文件名称);
    通过response.getOutputStream()向浏览器端输出

    Response禁用浏览器缓存

    发送http头,控制浏览器禁止缓存当前文档内容
    设置以下三个Http头信息禁用浏览器缓存
    Cache-Control : no-cache
    Expires: Thu, 01 Dec 1994 16:00:00 GMT (非常特殊,转换特定日期格式才可以)

    Javabean【实体类】 & servlet

    将jsp中java代码和html代码进行分离,将java代码写入到servlet中

    servlet主要负责业务逻辑,jsp只负责显示数据

     请求->找到servlet的过程:

    页面发送请求->web.xml->解析web.xml中url-pattern标签,获取值后
    和请求进行匹配(equals())->获取servlet-mapping标签中的
    servlet-name ->获取servlet标签中servlet-name,和mapping标签中
    的name进行匹配->获取servlet-class中的值-->Class.forName("类的完整路径").newInstance()

    baseServlet【加强反射】

    创建一个BaseServlet继承HttpServlet【重写service方法】

    这里的路径需要注意

    http://localhost:8080/B/UserServlet?method=login&name=Colin&pass=123
    这里的login就是方法的名字

    在service方法中

    package com.zym.servlet;

    import javax.servlet.ServletException;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;

    @WebServlet(name = "BaseServlet")
    public class BaseServlet extends HttpServlet {

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    String MethodName = req.getParameter("method");
    System.out.println(this);
    //com.zym.servlet.User_Servlet@163fc255
    Class<? extends BaseServlet> clazz = this.getClass();
    try {
    //获取方法对象
    Method method = clazz.getMethod(MethodName, HttpServletRequest.class, HttpServletResponse.class);

    //执行方法
    String path = (String ) method.invoke(this,req,resp);

    System.out.println("路径:"+path);

    if (path!=null) {
    System.out.println("页面跳转");
    req.getRequestDispatcher(path).forward(req,resp);
    }

    } catch (NoSuchMethodException e) {
    e.printStackTrace();
    } catch (IllegalAccessException e) {
    e.printStackTrace();
    } catch (InvocationTargetException e) {
    e.printStackTrace();
    }

    }

    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }
    }
    package com.zym.servlet;
    
    import javax.servlet.ServletException;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    
    @WebServlet(name = "User_Servlet")
    public class User_Servlet extends BaseServlet {
    
        public String  login(HttpServletRequest request,HttpServletResponse response){
    
         String name = request.getParameter("user");
            String pwd = request.getParameter("pwd");
    
            System.out.println(name+""+pwd);
    
            return "test.jsp";
        }

    Cookie

    Cookie是客户端技术,程序把每个用户的数据以cookie的形式写给用户各自的浏览器。当用户使用浏览器再去访问服务器中的web资源时,就会带着各自的数据去。这样,web资源处理的就是用户各自的数据了。

    Cookie会话技术的原理

    服务器创建cookie对象,把会话数据存储到cookie对象中。
    new Cookie("name","value");
    Cookie cookieName = new Cookie("NAME","Colin")
    Cookie cookiePass = new Cookie("PASS","123456")
    
    服务器发送cookie信息到浏览器
    response.addCookie(cookieName);
    response.addCookie(cookiePass);
    
    浏览器得到服务器发送的cookie,然后保存在浏览器端。
    
    浏览器在下次访问服务器时,会带着cookie信息
    
    服务器接收到浏览器带来的cookie信息
    request.getCookies();  返回Cookie[]

    核心技术点

    构造Cookie对象
    Cookie(java.lang.String name, java.lang.String value)
    
    设置cookie
    void setPath(java.lang.String uri)   :设置cookie的有效访问路径
    void setMaxAge(int expiry) : 设置cookie的有效时间,单位是秒
    void setValue(java.lang.String newValue) :设置cookie的值
    
    发送cookie到浏览器端保存
    void response.addCookie(Cookie cookie)  : 发送cookie
    
    服务器接收cookie
    Cookie[]    request.getCookies()  : 接收cookie

    Cookie会话技术的使用

    显示用户上次访问时间
    判断用户是否是第一次访问
    如果是第一次访问,需要输出欢迎,并且记录当前的时间,保存到cookie中,再回写到浏览器端。
    如果不是第一次访问,获取cookie中的时间,输出时间,并且记录当前的时间,保存到cookie中,再回写到浏览器端。

    Cookie细节

    一个Cookie只能标识一种信息,它至少含有一个标识该信息的名称(NAME)和设置值(VALUE)。


    一个WEB站点可以给一个WEB浏览器发送多个Cookie,一个WEB浏览器也可以存储多个WEB站点提供的Cookie。


    void setPath(java.lang.String uri) :设置cookie的有效访问路径。有效路径指的是cookie的有效路径保存在哪里,那么浏览器在有效路径下访问服务器时就会带着cookie信息,否则不带cookie信息。

    Cookie数据类型只能保存非中文字符串类型的。可以保存多个cookie,但是浏览器一般只允许存放300个Cookie,每个站点最多存放20个Cookie,每个Cookie的大小限制为4KB。

    void setMaxAge(int expiry) : 设置cookie的有效时间。
    正整数:表示cookie数据保存浏览器的缓存目录(硬盘中),数值表示保存的时间。
    负整数:表示cookie数据保存浏览器的内存中。浏览器关闭cookie就丢失了!!
    零:表示删除同名的cookie数据

    Session

    在WEB开发中,服务器可以为每个用户浏览器创建一个会话对象(session对象),注意:一个浏览器独占一个session对象(默认情况下)。因此,在需要保存用户数据时,服务器程序可以把用户数据写到用户浏览器独占的session中,当用户使用浏览器访问其它程序时,其它程序可以从用户的session中取出该用户的数据,为用户服务。

    Session的原理

    1)第一次访问创建session对象,给session对象分配一个唯一的ID,叫JSESSIONID
    2)把JSESSIONID作为Cookie的值发送给浏览器保存
    3)第二次访问的时候,浏览器带着JSESSIONID的cookie访问服务器
    4)服务器得到JSESSIONID,在服务器的内存中搜索是否存放对应编号的session对象。
    5)如果找到对应编号的session对象,直接返回该对象
    6)如果找不到对应编号的session对象,创建新的session对象,同时分配一个sessionId,然后继续走1的流程
    结论:通过JSESSION的cookie值在服务器找session对象!!!!!

    Session的核心技术点

    创建或得到session对象
    HttpSession getSession()   相当于 getSession(true)   getSession(false)
    HttpSession getSession(boolean create)  
    
    设置session对象
    void setMaxInactiveInterval(int interval)  : 设置session的有效时间,设置为-1的时候表示session永远不过期;
    void invalidate()     : 销毁session对象
    java.lang.String getId()  : 得到session编号
    
    保存会话数据到session对象
    void setAttribute(java.lang.String name, java.lang.Object value)  : 保存数据
    java.lang.Object getAttribute(java.lang.String name)  : 获取数据
    void removeAttribute(java.lang.String name) : 清除数据

    Session需要注意的细节

    三个getSession()方法的区别
    getSession(true) / getSession()  : 创建或得到session对象。没有匹配的session编号,自动创建新的session对象。
    getSession(false):    得到session对象。没有匹配的session编号,返回null
    
    Session对象销毁的时间    
        a. 默认情况30分钟服务器自动回收
        b.手动修改session回收时间,设置setMaxInactiveInterval(int interval)  (如果设置-1的话,表示永远不过期)
        c. 全局修改session有效时间,在web.xml里面设置全局的session有效时间   

    Servlet的数据访问范围

    application Scope  servletContext (数据库连接池,配置, 线程池, 站点访问次数) 
        每一个Web应用对应一个ServletContext
        存放所有用户都可以访问的数据
    session Scope HttpSession (存放与用户相关数据) 存放每个用户自己会话过程中的数据
    request Scope HttpServletRequest
    (Servlet处理结果,JSP显示) 数据存放在request对象中 生成新的请求时,原request存放数据丢失

    session和Cookie的区别

    (1)保存位置:session-服务器,cookie--客户端
    (2)保存数据不同:session存入后Object,Cookie--String
    (3)运行周期:session--浏览器访问期间,Cookie可以永久保存
    (4)安全性:session高于cookie

  • 相关阅读:
    一、redis的简介与安装
    三、Mybatis全局配置文件说明
    第七章、本地方法栈
    第六章、本地方法接口
    二、MyBatis接口开发
    第五章、虚拟机栈
    一、Mybatis入门
    第八章、声明式事务管理
    第七章、JdbcTemplate
    第六章、以XML方式配置切面
  • 原文地址:https://www.cnblogs.com/taozizainali/p/10997281.html
Copyright © 2020-2023  润新知