美文网首页后端java开发
最全的javaweb知识全集

最全的javaweb知识全集

作者: 墨线宝 | 来源:发表于2021-02-17 22:15 被阅读0次

    原文链接http://zhhll.icu/2021/javaweb/servlet/

    最全的javaweb知识全集

    Servlet是java定义的Servlet标准接口

    servlet容器负责Servlet和客户的通信以及调用Servlet的方法

    public interface Servlet {
        void init(ServletConfig var1) throws ServletException;
    
        ServletConfig getServletConfig();
    
        void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;
    
        String getServletInfo();
    
        void destroy();
    }
    

    servlet生命周期

    生命周期相关方法,servlet生命周期中的方法全是由servlet容器来调用的

    • 构造器
    • init方法
    • service方法
    • destory方法

    init方法

    init方法在第一次创建servlet时被调用,在后续每次请求时都不会被调用。

    当用户调用servlet的时候,该servlet的一个实例就会被创建,并且为每一个用户产生一个新的线程,init()用于进行一些初始化数据的加载和处理,这些数据会被用于servlet的整个生命周期

    void init(ServletConfig var1) throws ServletException;
    

    该方法是由servlet容器调用的

    重写init方法

    GenericServlet实现了Servlet和ServletConfig,是一个抽象类,并对init(ServletConfig var1)方法进行了一层封装,有一个ServletConfig成员变量,在init()方法中进行了初始化,使得可以直接在GenericServlet中直接使用ServletConfig方法

    而我们平时写Servlet大多是继承于HttpServlet类的,在对init方法进行重写时,重写不带参的init()方法即可

    //GenericServlet类
    
    public void init(ServletConfig config) throws ServletException {
        this.config = config;
        this.init();
    }
    
    public void init() throws ServletException {
    }
    

    该方法由GenericServlet的调用,如果需要使用到ServletConfig则调用getServletConfig()方法来获取

    service方法

    service方法是实际处理请求的方法,servlet容器调用service方法来处理请求,并将响应写会到客户端,每次服务器接收到一个新的servlet请求时,服务器会产生一个新的线程来调用服务

    void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;
    
    处理请求逻辑

    HttpServlet继承了GenericServlet,重写了service方法,将ServletRequest和ServletResponse转换为HttpServletRequest和HttpServletResponse,并根据不同的请求方式进行分发,doGet/doPost/doHead等

    servlet可以在任何协议下访问 ,写的Servlet必须实现Servlet接口,在http协议下可以使用HttpServlet ,用来给Web访问的

    在HttpServlet类中对于service()方法进行了处理,根据请求方式的不同,将请求分发到了不同的方法,而我们一般情况下写Servlet也是继承自HttpServlet的,所以在写请求处理逻辑时,只需要重写doGet()和doPost()方法即可

    // HttpServlet类
    
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String msg = lStrings.getString("http.method_get_not_supported");
        this.sendMethodNotAllowed(req, resp, msg);
    }
    
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            String msg = lStrings.getString("http.method_post_not_supported");
            this.sendMethodNotAllowed(req, resp, msg);
    }
    
    GET方法

    GET方法时浏览器向web服务器传递信息的默认方法,会在地址栏上产生很长的字符串,且GET方法有大小限制,请求字符串中最多只能有1024个字符

    POST方法

    POST方法不将请求信息放到地址中

    destroy方法

    destory()方法只在servlet生命周期结束时被调用一次。可以在destory()方法中进行一些资源的清理,如关闭数据库连接、停止后台线程等

    ServletContext接口

    • 该对象代表当前WEB应用,可以获取到web应用的信息
    • 可以使用ServletConfig的getServletContext()获取到ServletContext
    • 可以获取web应用的初始化参数,这是全局的方法,在web.xml中配置<context-param>
    • 获取web应用某个文件的绝对路径(在服务器上的路径,不是部署前的方法) getRealPath
    • 获取当前应用的名称 getContextPath
    • 获取当前web应用的某一个文件对应的输入流 getResourceAsStream() path是相对于当前web应用的根目录

    servlet容器

    在上面介绍servlet生命周期时,多次提到了servlet容器,其实在设计Servlet时,J2EE jdk只是提供了一个标准,在javax.servlet包以及子包下,而真正的实现是由servlet容器来进行实现的,如tomcat是在servlet-api.jar中实现的

    servlet容器
    1、可以创建servlet,并调用servlet的相关生命周期方法
    2、JSP、Filter、Listener

    下面将以tomcat作为servlet容器为例介绍web应用

    web应用

    WEB-INF

    静态页面不要放在WEB-INF下,WEB-INF是给tomcat用的

    WEB-INF 对于web应用的描述

    - web.xml 必须符合J2EE标准
    - lib  放jar包
    - 
    

    tomcat配置项目位置

    tomcat映射配置任意目录的项目
    在conf下新建catalina文件夹,新建localhost文件夹,
    在其中新建一个xml文件,文件名是url根路径
    path当前没用 docBase为项目路径(编译之后的项目)

    <Context path="" docBase="" reloadable="true">
    

    web.xml配置servlet

    load-on-startup参数指定servlet创建的时机 若为负数,则在第一次请求时被创建,若为0或者正数,在web应用被Servlet容器加载时创建实例,值越小越早被启动

    init方法有入参 ServletConfig
    配置ServletConfig

    <!-- 注意servlet和servlet-mapping都是成对出现的 -->
    <servlet>
      <servlet-name>HW</servlet-name>
      <servlet-class>com.zhanghe.study.servlet.HelloWorldServlet</servlet-class>
        <!-- 配置servlet初始化init时中ServletConfig参数-->
      <init-param>
        <param-name>name</param-name>
        <param-value>john</param-value>
      </init-param>
      <!-- servlet加载时机 -->
      <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
      <!-- 对应servlet标签中的servlet-name值 -->
      <servlet-name>HW</servlet-name>
      <url-pattern>/</url-pattern>
    </servlet-mapping>
    
    获取ServletConfig值
    
    // 获取指定的属性
    config.getInitParameter("name")
    // 获取所有的属性
    config.getInitParameters()
    

    请求转发和请求重定向

    // 请求转发
    request.getRequestDispatcher(url).forward(req,resp)
    // 请求重定向
    response.sendRedirect(url)
    

    本质区别:请求转发只向服务器发起一次请求,重定向发起两次请求
    1、
    请求转发:地址是初次发出请求的地址
    重定向:地址栏是最后响应的地址

    2、
    请求转发:在最终的Servlet中,request对象和中转的那个request是同一个对象
    重定向:在最终的Servlet中,request对象和中转的那个request不是同一个对象

    3、
    请求转发:只能转发到当前web应用
    请求重定向:可以重定向到任何资源

    4、
    请求转发:/代表当前web应用的根目录
    请求重定向:/代表当前web站点的根目录,要使用request.getContextPath()再加上路径

    会话管理

    HTTP是无状态的协议,每次客户端访问web页面时,都会打开一个单独的连接到web服务器,服务器不会自动保存客户端请求的任何记录,需要使用cookie和session来将一系列的请求和响应关联起来,维持客户端和服务器之间的会话

    cookie

    Cookie是存储在计算机上的文本文件,用于追踪各种信息,记录在客户端,浏览器可以禁用cookie,可以删除cookie,
    在服务器产生,作为响应头的一部分返回给客户端,浏览器收到cookie后,把cookie的键值写入到文本中,发送请求时浏览器会把cookie信息与请求发送给服务器

    cookie原理

    底层原理:WEB服务器通过在HTTP响应消息中增加Set-Cookie响应头字段将Cookie信息发送给浏览器,浏览器则通过在HTTP请求信息中增加Cookie请求头字段将Cookie回传给WEB服务器

    操作cookie
    创建cookie
    // 第一个参数是cookie的键,第二个参数是cookie的值
    Cookie cookie = new Cookie("name","value")
    resp.addCookie(cookie)
    
    获取cookie
    Cookie[] cookies = req.getCookies();
    
    设置cookie的一些方法
    // 描述cookie的注释
    public void setComment(String purpose) {
      this.comment = purpose;
    }
    // 设置cookie适用的域名
    public void setDomain(String pattern) {
      this.domain = pattern.toLowerCase(Locale.ENGLISH);
    }
    // 设置过期时间(单位是秒),如果不设置,cookie在当前session中有效
    // 如果设置生命周期会写在文件里
    // 如果不设置生命周期会写在浏览器内存里,窗口关闭,cookie就没了
    public void setMaxAge(int expiry) {
      this.maxAge = expiry;
    }
    
    // 设置cookie适用的路径,如果不指定,在当前目录及其子目录的URL下会返回cookie
    public void setPath(String uri) {
      this.path = uri;
    }
    
    // 是否只在加密的连接上(SSL)发送
    public void setSecure(boolean flag) {
      this.secure = flag;
    }
    
    // 设置cookie值
    public void setValue(String newValue) {
      this.value = newValue;
    }
    
    
    public void setVersion(int v) {
      this.version = v;
    }
    
    获取cookie属性的方法
    // 获取cookie的注释,如果没有为null
    public String getComment() {
      return this.comment;
    }
    // 获取cookie适用的域名
    public String getDomain() {
      return this.domain;
    }
    // 获取cookie过期时间,如果为-1,cookie表示持续到浏览器关闭
    public int getMaxAge() {
      return this.maxAge;
    }
    // 获取cookie适用的路径
    public String getPath() {
      return this.path;
    }
    // 获取是否只在加密的连接上发送
    public boolean getSecure() {
      return this.secure;
    }
    // cookie的名称,创建后不可修改
    public String getName() {
      return this.name;
    }
    // 获取cookie值
    public String getValue() {
      return this.value;
    }
    
    public int getVersion() {
      return this.version;
    }
    
    删除cookie

    设置生命周期 cookie.setMaxAge()方法设置,秒为单位,若为0,表示立即删除该cookie,将该cookie放到响应中返回

    注意:一个servlet设置的cookie可以被同一个路径下或者子路径下的servlet读到,其他访问不到

           路径是指url可以通过cookie.setPath()方法设置cookie的作用范围
    
    cookie适用场景
    • 自动登录,不需要填写用户名和密码
    • 浏览记录

    session

    session是记录在服务器端,获取session需要把sessionId传递给服务端,通过sessionId来取到对应的session,关闭浏览器,session不会被销毁,还可以通过sessionId找到该session,在同一个application下的servlet/jsp可以共享一个session,前提是同一个客户端窗口

    操作session
    创建或获取session
    // 若为false,如果当前没有关联的session,如返回null;若为true,如果没有则会创建 默认是true
    HttpSeesion session = request.getSession(true); 
    
    session的相关方法
    // 返回session的创建时间(单位毫秒)
    long getCreationTime();
    // 获取sessionId
    String getId();
    // 返回客户端最后一次发送与该session会话相关的请求的时间(单位毫秒)
    long getLastAccessedTime();
    
    ServletContext getServletContext();
    // session的过期时间,单位秒
    // 也可以在web.xml中设置过期时间,单位为分钟,tomcat默认是30分钟
    // <session-config>
    //  <session-timeout15></session-timeout>
    // </session-config>
    void setMaxInactiveInterval(int var1);
    // 返回servlet容器在客户端访问时保持session会话打开的最大时间间隔,单位秒
    int getMaxInactiveInterval();
    // 返回seesion会话中该名称的对象,没有返回null
    Object getAttribute(String var1);
    // 返回该session会话中所有的名称
    Enumeration<String> getAttributeNames();
    // 将对象绑定到该session会话中
    void setAttribute(String var1, Object var2);
    // 移除指定名称的对象
    void removeAttribute(String var1);
    // 使该session无效
    void invalidate();
    // 是否为新创建的session(客户端还不知道该session)
    boolean isNew();
    
    // 判断当前请求的session是否合法
    req.isRequestedSessionIdValid();
    // 判断当前请求是不是从URL发出的
    req.isRequestedSessionIdFromURL();
    // 判断当前请求是不是从cookie发出的
    req.isRequestedSessionIdFromCookie();
    
    session的实现方式

    session有两种实现方式
    通过cookie来实现 第一次请求时,响应在响应头set-Cookie中 有sessionId,把sessionId放到cookie中,如果浏览器支持cookie,会把sessionId放到cookie中
    默认是存储在内存中的,没有存储在磁盘上,关闭浏览器就会失效
    可以进行持久化,使用cookie.setMaxAge

    通过URL重写来实现
    response.encodeURL两个作用

    • 转码
    • URL后加上sessionID

    过滤器Filter

    可以对请求和响应进行拦截,在访问后端资源之前,拦截这些来自客户端的请求,在发送回客户端之前,处理这些响应

    过滤器的类型

    • 身份验证过滤器
    • 数据压缩过滤器
    • 加密过滤器
    • 触发访问事件资源的过滤器
    • 图像转换过滤器
    • 日志记录和审核过滤器
    • MIME-类型链过滤器
    • Tokenizing过滤器
    • 转换XML内容的XSL/T过滤器

    过滤器的使用

    需要实现Filter接口

    public interface Filter {
        // 由servlet容器调用,指示一个过滤器被放入服务
        void init(FilterConfig var1) throws ServletException;
            // 在每次一个请求或响应在所对应的资源下时通过链传递,由容器调用
        void doFilter(ServletRequest var1, ServletResponse var2, FilterChain var3) throws IOException, ServletException;
            // 由servlet容器调用,指示一个过滤器从服务去除
        void destroy();
    }
    
    在web.xml中配置写好的Filter
    
    <filter>
      <filter-name>security</filter-name>
      <filter-class>com.zhanghe.study.webstudy.filter.SecurityFilter</filter-class>
      <!--用户名-->
      <init-param>
        <param-name>userName</param-name>
        <param-value>john</param-value>
      </init-param>
    </filter>
    
    <!-- 拦截的顺序与在web.xml中 filter-mapping的配置顺序有关,靠前的先被调用 -->
    <filter-mapping>
      <filter-name>security</filter-name>
      <url-pattern>/*</url-pattern>
      <!-- 在filter-mapping中有一个dispatcher标签,指定过滤器所拦截的资源被Servlet容器的调用方式
                    可以是REQUEST,INCLUDE,FORWARD和ERROR,默认是REQUEST
                    可以指定多个dispatcher来指定Filter对资源的多种调用方式进行拦截 -->
      <dispatcher>REQUEST</dispatcher>
    </filter-mapping>
    

    异常处理

    当servlet出现异常时,servlet容器使用exception-type元素来找到与抛出的异常类型相匹配的配置

    public class ExceptionHandler extends HttpServlet {
    
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            Throwable throwable = (Throwable) req.getAttribute("javax.servlet.error.exception");
            Integer code = (Integer) req.getAttribute("javax.servlet.error.status_code");
            String message = (String) req.getAttribute("javax.servlet.error.message");
            System.out.println("=========");
            System.out.println(throwable);
            System.out.println("=========");
            System.out.println(code);
            System.out.println("=========");
            System.out.println(message);
        }
    }
    
    <!-- 配置异常处理的servlet -->
    <servlet>
        <servlet-name>ExceptionHandler</servlet-name>
        <servlet-class>com.zhanghe.study.servlet.ExceptionHandler</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>ExceptionHandler</servlet-name>
        <url-pattern>/ExceptionHandler</url-pattern>
    </servlet-mapping>
    <!-- 配置哪些错误码会调用该异常处理类 -->
    <error-page>
        <error-code>404</error-code>
        <location>/ExceptionHandler</location>
    </error-page>
    <!-- 配置哪些异常类型会调用该异常处理类 -->
    <error-page>
        <exception-type>java.lang.ArithmeticException</exception-type>
        <location>/ExceptionHandler</location>
    </error-page>
    

    如果出现异常,会在请求域中设置相应的属性

    可以使用request.getAttribute("")取出

    javax.servlet.error.status_code //错误码,Integer类型
    javax.servlet.error.exception_type  // 异常类型,Class类型
    javax.servlet.error.message    //异常信息,String类型
    javax.servlet.error.request_uri  //出现异常的uri地址,String类型
    javax.servlet.error.exception  //异常,Throwable类型
    javax.servlet.error.servlet_name  //servlet名称,String类型
    

    上传文件

    <!-- 上传文件一定要使用post请求
             enctype需要设置为multipart/form-data
         input标签的type类型设为file
    -->
    <form method="post" enctype="multipart/form-data">
    <input type="file" name="file">
    

    form表单的编码格式
    ①application/x-www-form-urlencoded 默认 在发送前编码所有字符
    ②multipart/form-data 不对字符编码,二进制
    ③text/plain 空格转换为+号,但不对特殊字符编码

    使用读取流的方式来读取太过于麻烦 request.getInputStream() 获取到的是整个请求体,需要解析各个字段和分隔
    解析multipart/form-data比较复杂
    可以使用外部依赖包
    commons-fileupload.jar 依赖于 commons-io.jar

    <!-- 文件上传 -->
    <dependency>
      <groupId>commons-fileupload</groupId>
      <artifactId>commons-fileupload</artifactId>
      <version>1.4</version>
    </dependency>
    

    commons-fileupload解析请求,解析成FileItem集合,无论是文本域还是文件域
    使用FileItem.isFormField()来判断是不是一个表单域
    表单域 item.getFieldName item.getString

    非表单域  item.getFieldName  item.getName   item.getContentType  item.isImemory  item.getSize   item.getInputStream
    

    转发和重定向

    国际化

    • 国际化(i18n): i18n internationalization,网站能够提供翻译成访问者的语言或国籍的不同版本的内容
    • 本地化(i10n): 向网站添加资源,使其适应特定的地理或文化区域,例如将网站翻译为中文
    • 区域设置:通常为语言符号后跟一个由下划线分隔的国家符号。例如"en_US"

    获取区域

    //获取当前国家和语言
    Locale locale = request.getLocale();
    

    获取区域设置

    // 获取该区域设置的国家
    public String getCountry() {
      return baseLocale.getRegion();
    }
    // 获取该区域设置的国家名称
    public final String getDisplayCountry() {
      return getDisplayCountry(getDefault(Category.DISPLAY));
    }
    // 获取该区域设置的语言代码
    public String getLanguage() {
      return baseLocale.getLanguage();
    }
    // 获取该区域设置的语言名称
    public final String getDisplayLanguage() {
      return getDisplayLanguage(getDefault(Category.DISPLAY));
    }
    // 返回该区域设置的国家的三个字母缩写
    public String getISO3Country() throws MissingResourceException {
      String country3 = getISO3Code(baseLocale.getRegion(), LocaleISOData.isoCountryTable);
      if (country3 == null) {
        throw new MissingResourceException("Couldn't find 3-letter country code for "
                                           + baseLocale.getRegion(), "FormatData_" + toString(), "ShortCountry");
      }
      return country3;
    }
    // 返回该区域设置的语言的三个字母缩写
    public String getISO3Language() throws MissingResourceException {
      String lang = baseLocale.getLanguage();
      if (lang.length() == 3) {
        return lang;
      }
    
      String language3 = getISO3Code(lang, LocaleISOData.isoLanguageTable);
      if (language3 == null) {
        throw new MissingResourceException("Couldn't find 3-letter language code for "
                                           + lang, "FormatData_" + toString(), "ShortLanguage");
      }
      return language3;
    }
    

    时间国际化

    时间格式化 DateFormat

    货币国际化

    数字、货币格式化 NumberFormat

    字符串国际化

    字符串格式化 MessageFormat

    String str = "Date: {0},Salary: {1}";
    Locale locale = Locale.CHINA;
    Date date = new Date();
    double sa1 = 12345.12;
    MessageFormat.format(str,date,sa1);
    

    国际化配置

    native2ascii命令在jdk下 可以查看ascii码

    Locale locale = Locale.CHINA;
    ResourceBundle bundle = ResourceBundle.getBundle("i18n",locale);
    

    在配置文件中i18n.properties i18n_en_US.properties i18n_zh_CN.properties
    根据locale来找不同的配置文件

    中文乱码问题
    GET请求 ①tomcat的server.xml文件中,在Connector 节点中添加useBodyEncodingForURI="true" 属性 使用请求体的编码,然后在获取请求内容之前使用request.setCharacterEncoding("UTF-8")
    ②tomcat的server.xml文件中,在Connector 节点中添加URIEncoding="UTF-8"属性
    ③tomcat的get请求默认使用ISO-8859-1来编码,可以在获取的时候进行转码,new String(request.getParameter("name").getBytes("ISO-8859-1"),"UTF-8")

    多个请求使用同一个Servlet
    第一种方案:在url加上入参method
    根据method进行分发

    第二种方案:
    web.xml使用*.do来匹配Servlet
    根据 request.getServletPath()然后反射调用方法
    

    表单的重复提交
    重复提交的情况
    ①在表单提交到一个Servlet,Servlet又通过请求转发的方式响应了一个页面,此时地址栏还保留着Servlet的那个路径,在响应页面点击刷新
    ②在响应页面没有到达时重复点击提交按钮
    ③点击返回,再点击提交

    不是重复提交的情况
    ①点击返回之后,刷新页面,再点击提交

    如何避免表单的重复提交
    使用session,生成属性,移除属性

    HttpServletRequestWrapper类包装原始的request对象,实现了HttpServletRequest接口的所有方法,内部调用了所包装的
    request对象的对应方法
    相应的也有HttpServletResponseWrapper类来包装原始的response对象
    继承HttpServletRequestWrapper,重写

    Servlet监听器
    用于监听ServletContext、HttpSession、ServletRequest等对象的创建和销毁,以及属性修改

    ①监听ServletContext、HttpSession、ServletRequest等对象的创建和销毁
    ServletContextListener 创建contextInitialized 销毁contextDestroyed
    HttpSessionListener 创建sessionCreated 销毁sessionDestroyed
    ServletRequestListener 创建requestInitialized 销毁requestDestroyed

    实现相应的接口,监听不同的域对象
    web.xml
    <listener>
        <listener-class>
    
    场景:
        ServletContextListener最常用,在当前WEB应用加载的时候对当前WEB应用的相关资源进行初始化操作:创建数据库连接池,创建Spring的IOC容器,读取当前WEB应用的初始化参数
    

    ②监听域对象 ServletContext、HttpSession、ServletRequest 属性变更的监听器
    ServletContextAttributeListener attributeAdded attributeRemoved attributeReplaced
    HttpSessionAttributeListener attributeAdded attributeRemoved attributeReplaced
    ServletRequestAttributeListener attributeAdded attributeRemoved attributeReplaced
    ServletRequestAttributeEvent 可以getName、getValue或者值

    ③感知session绑定的监听器
    保存到Session域中的对象可以有多种状态:绑定到Session中,从Session中解除绑定;随Session对象持久到到一个存储设备中;随Session对象从一个存储设备中恢复
    HttpSessionBindingListener和HttpSessionActivationListener接口,实现这两个接口不需要在web.xml文件中注册

    放到session中的对象实现HttpSessionBindingListener
        会触发两个方法   绑定valueBound        解除valueUnBanding
    
    
    实现了HttpSessionActivationListener接口的对象可以感知自己被钝化和被活化的事件
        sessionWillPassivate 从内存写到磁盘     sessionDisActivate 从磁盘中读取出来
    
        session会被存储在tomcat当前项目下  .cer文件
    

    由于本身的博客百度没有收录,博客地址http://zhhll.icu

    相关文章

      网友评论

        本文标题:最全的javaweb知识全集

        本文链接:https://www.haomeiwen.com/subject/mdmwxltx.html