精华内容
下载资源
问答
  • servlet钩子
    2021-01-17 13:14:54

    import org.springframework.boot.SpringApplication;

    import org.springframework.boot.autoconfigure.EnableAutoConfiguration;

    import org.springframework.boot.autoconfigure.SpringBootApplication;

    import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;

    import org.springframework.boot.web.support.SpringBootServletInitializer;

    import org.springframework.context.annotation.Bean;

    @SpringBootApplication

    @EnableAutoConfiguration

    public class Application extends SpringBootServletInitializer {

    public static void main(

    String[] args) {

    SpringApplication.run(Application.class,

    args);

    }

    @NotNull

    @Bean

    ServletListenerRegistrationBean myServletListener() {

    ServletListenerRegistrationBean srb =

    new ServletListenerRegistrationBean<>();

    srb.setListener(new ExampleServletContextListener());

    return srb;

    }

    }

    import javax.servlet.ServletContextEvent;

    import javax.servlet.ServletContextListener;

    public class ExampleServletContextListener implements ServletContextListener {

    @Override

    public void contextInitialized(

    ServletContextEvent sce) {

    // Context Initialised

    }

    @Override

    public void contextDestroyed(

    ServletContextEvent sce) {

    // Here - what you want to do that context shutdown

    }

    }

    更多相关内容
  • 答:一般情况下当服务器收到要访问这个servlet的请求后,这个servlet实例对象就会被创建,而且只创建一次,后面如果有同样的请求,那么就会访问已经创建好的实例对象(这也说明了,为什么第一次访问servlet的时候会...

    出处:http://blog.csdn.net/world_java/article/details/8979951

    http://localhost:9090/xxx.html?userName=xxc

    问:为何html静态页面也能接收参数?

    答:xxc.html并不是一个真正的html页面,而是在web.xml文件中经过了映射而已。

    [html]  view plain copy print ?
    1. <servlet>  
    2.     <servlet-name>servletday1</servlet-name>  
    3.     <servlet-class>cn.xxc.servletday1.FirstServlet</servlet-class>  
    4. </servlet>  
    5.     
    6. <servlet-mapping>  
    7.     <servlet-name>servletday1</servlet-name>  
    8.     <url-pattern>/xxc.com</url-pattern>  
    9. </servlet-mapping>  


    问:servlet在容器中的实例对象可以被创建多次么?

    答:一般情况下当服务器收到要访问这个servlet的请求后,这个servlet实例对象就会被创建,而且只创建一次,后面如果有同样的请求,那么就会访问已经创建好的实例对象(这也说明了,为什么第一次访问servlet的时候会比后面访问的速度要慢)。但是如果在web.xml中多次注册了这个servlet,那么servlet在容器中的实例对象就可以被创建多次(注册几次就创建几次)。

    [html]  view plain copy print ?
    1. <servlet>  
    2.     <servlet-name>servletday1</servlet-name>  
    3.     <servlet-class>cn.xxc.servletday1.FirstServlet</servlet-class>  
    4. </servlet>  
    5. <!-- 再次注册同一个servlet,但是servletName必须不一样 -->  
    6. <servlet>  
    7.     <servlet-name>servletday2</servlet-name>  
    8.     <servlet-class>cn.xxc.servletday1.FirstServlet</servlet-class>  
    9. </servlet>  
    10.    
    11. <servlet-mapping>  
    12.     <servlet-name>servletday1</servlet-name>  
    13.     <url-pattern>/pkq.com</url-pattern>  
    14. </servlet-mapping>  


    问:一个servlet可以被映射多次么?

    答:可以。如下创建就可以用两种url来访问。

    (1)http://localhost:9090/项目名/xxc.com

    (2)http://localhost:9090/项目名/pkq.com

    [html]  view plain copy print ?
    1. <servlet>  
    2.     <servlet-name>servletday1</servlet-name>  
    3.     <servlet-class>cn.xxc.servletday1.FirstServlet</servlet-class>  
    4. </servlet>  
    5.     
    6. <servlet-mapping>  
    7.     <servlet-name>servletday1</servlet-name>  
    8.     <url-pattern>/xxc.com</url-pattern>  
    9.     <url-pattern>/pkq.com</url-pattern>  
    10. </servlet-mapping>  


    servlet的*通配符:

    在Servlet映射到的URL中也可以用*通配符,但是只能有两种固定的格式:

    (1)*.扩展名” 

    (2)以正斜杠(/)开头并以“/*”结尾。

    注意:正斜杠(/)后的*不能带扩展名,即不能设置为“/action/*.xx”形式


    Servlet映射的最具体匹配规则:

    对于如下的一些映射关系:

    /abc/*映射到Servlet1

    /*映射到Servlet2

    /abc映射到Servlet3

    *.do映射到Servlet4

    将发生如下一些行为:

    当请求URL为“/abc/a.html”,“/abc/*”和“/*”都可以匹配这个URL,

    Servlet引擎将调用Servlet1 

    当请求URL为“/abc”,“/*”和“/abc”都可以匹配这个URL,

    Servlet引擎将调用Servlet3

    当请求URL为“/a.do”,“/*”和“*.do”都可以匹配这个URL,

    Servlet引擎将调用Servlet2

    当请求URL为“/xxx/yyy/a.do”时,“/*”和“*.do”都可以匹配这个URL

    Servlet引擎将调用Servlet2

    匹配原则总结:

    目录格式优先级大于后缀名格式。如果同是目录格式或者后缀名格式,哪个更像哪个匹配。


    问:为何在访问http://localhost:9090/项目名/a.html时,就能访问到a.html这个页面?

    答:因为在tomcat下的conf目录下有一个web.xml文件,这个文件中有如下一段配置信息。这个默认的servlet会去硬盘上找a.html网页返回给浏览器。

    [html]  view plain copy print ?
    1. <servlet>  
    2.         <servlet-name>default</servlet-name>  
    3.         <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>  
    4.         <init-param>  
    5.             <param-name>debug</param-name>  
    6.             <param-value>0</param-value>  
    7.         </init-param>  
    8.         <init-param>  
    9.             <param-name>listings</param-name>  
    10.             <param-value>false</param-value>  
    11.         </init-param>  
    12.         <load-on-startup>1</load-on-startup>  
    13. </servlet>  
    14.   
    15.   
    16. <servlet-mapping>  
    17.         <servlet-name>default</servlet-name>  
    18.         <url-pattern>/</url-pattern>  
    19. </servlet-mapping>  


    Servlet的生命周期:

    1.web容器检查是否已经装载并创建了该Servlet的实例对象。如果是,则执行第四步,否则,这行第二步。

    2.装载并创建该Servlet的一个实例对象。

    3.调用Servlet实例对象的inint()方法。

    4.创建一个用于封装HTTP请求消息的HttpServletRequest对象和一个代表HTTP响应消息的HttpServletResponse对象,然后调用Servlet的service()方法,并将请求和响应对象作为参数传递进去。

    5.WEB应用程序被停止或重新启动之前,WEB容器将卸载Servlet,并在卸载之前调用Servlet的destroy()方法。


    特赦情况:

    为了防止第一个访问Servlet的用户看到生成后的网页所需要的时间比第二个慢的情况。我们可以在WEB容器启动这个WEB程序的时候就进行加载并创建实例对象(不需要发出请求)。

    [html]  view plain copy print ?
    1. <servlet>  
    2.     <servlet-name>servletday1</servlet-name>  
    3.     <servlet-class>cn.xxc.servletday1.FirstServlet</servlet-class>  
    4.     <load-on-startup>1</load-on-startup><!--启动时加载,数字是1至5,越小越优先,如果相同则按顺序加载-->  
    5. </servlet>  



    Servlet的构造方法和init方法的区别:

    1.构造方法是JVM调用,init方法是由tomcat调用。

    2.构造方法要优先于init方法调用,原因也很好理解:因为要先有Servlet这个实例对象,才能使WEB容器去调用。

    3.init方法中有HttpServletRequest和HttpServletResponse两个参数。但是构造方法里却没有。所以不能说将init()里的步骤可以放到构造方法里去执行。



    Tomcat将Servlet的一些配置信息都封装在ServletConfig对象中

     java.lang.StringgetInitParameter(java.lang.String name)
              Returns a String containing the value of the named initialization parameter, ornull if the parameter does not exist.
     java.util.EnumerationgetInitParameterNames() 
              Returns the names of the servlet's initialization parameters as an Enumeration of String objects, or an emptyEnumeration if the servlet has no initialization parameters.
     ServletContextgetServletContext() 
              Returns a reference to the ServletContext in which the caller is executing.    获取上下文对象
     java.lang.StringgetServletName() 
              Returns the name of this servlet instance.

    Web.xml中的全局和局部配置信息

    [html]  view plain copy print ?
    1. <context-param><!--全局初始化参数 -->  
    2.     <param-name>userName</param-name>  
    3.     <param-value>术士</param-value>  
    4.   </context-param>  
    5.   <servlet>  
    6.     <servlet-name>servletday1</servlet-name>  
    7.     <servlet-class>cn.xxc.servletday1.FirstServlet</servlet-class>  
    8.     <init-param><!-- 注意这个标签必须紧跟servlet-class标签 -->  
    9.         <param-name>name1</param-name>  
    10.         <param-value>萨满</param-value>  
    11.     </init-param>  
    12.     <init-param>  
    13.         <param-name>name2</param-name>  
    14.         <param-value>法师</param-value>  
    15.     </init-param>  
    16.     <load-on-startup>1</load-on-startup>  
    17.   </servlet>  

    获取Web.xml中的配置信息

    [java]  view plain copy print ?
    1. private ServletConfig config;  
    2.   
    3. @Override  
    4. public void init(ServletConfig config) throws ServletException {  
    5.     this.config = config;  
    6. }  
    7.   
    8. @Override  
    9. public void service(ServletRequest request, ServletResponse response)  
    10.         throws ServletException, IOException {  
    11.     System.out.println("ServletName--->"+config.getServletName());//获取Servlet的名字  
    12.     Enumeration<String> configs = config.getInitParameterNames();//获取Servlet的初始化信息 name值,是枚举类型  
    13.     while(configs.hasMoreElements()){  
    14.         String name = configs.nextElement();  
    15.         String value = config.getInitParameter(name);//根据name值,获取value  
    16.         System.out.println(name+"  --------------  "+value);  
    17.     }  
    18.   
    19.   
    20.     ServletContext context = config.getServletContext();  
    21.     String value = context.getInitParameter("userName");//获取全局初始化参数  
    22.     System.out.println(value);  
    23. }  


    以下是一个实现了Servlet接口的自定义的Servlet   需要实现5个方法

    [java]  view plain copy print ?
    1. package cn.xxc.servletday1;  
    2.   
    3. import java.io.IOException;  
    4.   
    5. import javax.servlet.Servlet;  
    6. import javax.servlet.ServletConfig;  
    7. import javax.servlet.ServletException;  
    8. import javax.servlet.ServletRequest;  
    9. import javax.servlet.ServletResponse;  
    10.   
    11. public class FirstServlet implements Servlet {  
    12.   
    13.     @Override  
    14.     public void init(ServletConfig paramServletConfig) throws ServletException {//tomcat在调用Servlet时,初始化会自动调用此方法,只会调用一次   
    15.           
    16.     }  
    17.   
    18.     @Override  
    19.     public ServletConfig getServletConfig() {  
    20.         return null;  
    21.     }  
    22.   
    23.     @Override  
    24.     public void service(ServletRequest paramServletRequest,  
    25.             ServletResponse paramServletResponse) throws ServletException,  
    26.             IOException {//当用户发送一次请求到这个Servlet时,会调用这个方法  
    27.           
    28.     }  
    29.   
    30.     @Override  
    31.     public String getServletInfo() {  
    32.         return null;  
    33.     }  
    34.   
    35.     @Override  
    36.     public void destroy() {//Web应用程序在卸载或重启前会调用此方法  
    37.           
    38.     }  
    39.   
    40. }  


    我们发现每次写一个Servlet都需要实现Servlet接口,并且要覆写5个方法,而且这5个方法并不是全部会用到,这样就有些不足。

    这时我们可以让自己写的Servlet继承GenericServlet类

    [java]  view plain copy print ?
    1. package cn.xxc.servletday1;  
    2.   
    3. import java.io.IOException;  
    4.   
    5. import javax.servlet.GenericServlet;  
    6. import javax.servlet.ServletConfig;  
    7. import javax.servlet.ServletException;  
    8. import javax.servlet.ServletRequest;  
    9. import javax.servlet.ServletResponse;  
    10.   
    11. public class FirstServlet extends GenericServlet {  
    12.   
    13.     @Override  
    14.     public void service(ServletRequest paramServletRequest,  
    15.             ServletResponse paramServletResponse) throws ServletException,  
    16.             IOException {  
    17.         /* 
    18.          * 为什么这样就能取到ServletConfig? 
    19.          * 请看GenericServlet源码。 
    20.          */  
    21.         ServletConfig config = this.getServletConfig();  
    22.     }  
    23.   
    24. }  

    GenericServlet类源码

    [java]  view plain copy print ?
    1. package javax.servlet;  
    2.    
    3.  import java.io.IOException;  
    4. import java.io.Serializable;  
    5. import java.util.Enumeration;  
    6.   
    7. import javax.servlet.Servlet;  
    8. import javax.servlet.ServletConfig;  
    9. import javax.servlet.ServletContext;  
    10. import javax.servlet.ServletException;  
    11. import javax.servlet.ServletRequest;  
    12. import javax.servlet.ServletResponse;  
    13.    
    14.  public abstract class GenericServlet  
    15.    implements Servlet, ServletConfig, Serializable{  
    16.    private transient ServletConfig config;  
    17.    
    18.    public void destroy(){//覆写Servlet中的销毁方法  
    19.    }  
    20.    
    21.    public String getInitParameter(String name){  
    22.        return getServletConfig().getInitParameter(name);  
    23.    }  
    24.    
    25.    public Enumeration getInitParameterNames(){  
    26.        return getServletConfig().getInitParameterNames();  
    27.    }  
    28.    
    29.    public ServletConfig getServletConfig(){  
    30.      //这里就解释了为何实现了GenericServlet的子类可直接ServletConfig config = this.getServletConfig();  
    31.        return this.config;  
    32.    }  
    33.    
    34.    public ServletContext getServletContext(){  
    35.        return getServletConfig().getServletContext();  
    36.    }  
    37.    
    38.    public String getServletInfo(){  
    39.        return "";  
    40.    }  
    41.    
    42.    public void init(ServletConfig config)//覆写Servlet接口的初始化方法  
    43.      throws ServletException{  
    44.         this.config = config;  
    45.         init();  
    46.         /* 
    47.          * 这种函数称为钩子函数 
    48.          * 既然继承了GenericServlet,它给我们提供了什么样的简便呢? 
    49.          *      GenericServlet覆写了init(ServletConfig config)然后在其中又调用一个自定函数init() 
    50.          *      在子类中只需要覆写init()方法即可,即不需要做像this.config = config赋值操作【最主要的方便就是省略了这句话】 
    51.          * 为何在destroy函数中不定义这种钩子函数 
    52.          *      没必要,因为destroy函数是无参的,即不需要做像this.config = config赋值操作 
    53.          * 在GenericServlet中init()方法为空 
    54.          * 当一个类继承了GenericServlet,如果需要在初始化函数中加入一些操作,那么就可以覆写GenericServlet中的init()方法 
    55.          * 这样做的原因是因为tomcat调用初始化方法必定是init(ServletConfig config)而不会去调用自定义的init() 
    56.          */  
    57.    }  
    58.    
    59.    public void init() throws ServletException{  
    60.    }  
    61.    
    62.    public void log(String msg){  
    63.        getServletContext().log(getServletName() + ": " + msg);  
    64.    }  
    65.    
    66.    public void log(String message, Throwable t){  
    67.        getServletContext().log(getServletName() + ": " + message, t);  
    68.    }  
    69.    
    70.    public abstract void service(ServletRequest paramServletRequest, ServletResponse paramServletResponse)  
    71.      throws ServletException, IOException;  
    72.    
    73.    public String getServletName(){  
    74.        return this.config.getServletName();  
    75.    }  
    76.  }  


    GenericServlet还不足以满足我们的需求,比如获取用户的IP地址,是在HttpServletRequest类中才有的方法,需要把ServletRequest强转。

    但是每次强转又显得不足,这时我们可以继承HttpServlet来解决这个问题。(HttpServlet继承了GenericServlet)

    而且Http请求方式又有好几种,每种方式都对应不同的方法。如果使用ServletRequest,那么就需要我们自己去判断到底是get,post,put,delete,options,trace。这样也很麻烦。

    所以此时,我们可以用HttpServletRequest。

    摘取HttpServletRequest源码中的两个方法就能明白它是怎么运行的。

    [java]  view plain copy print ?
    1. public void service(ServletRequest req, ServletResponse res) //强转,并且返回强转后的结果  
    2.         throws ServletException, IOException{  
    3.     HttpServletRequest request;  
    4.     HttpServletResponse response;  
    5.     try{  
    6.             request = (HttpServletRequest)req;  
    7.             response = (HttpServletResponse)res;  
    8.     } catch (ClassCastException e) {  
    9.         throw new ServletException("non-HTTP request or response");  
    10.   }  
    11.         service(request, response);  
    12. }  
    13.   
    14.   
    15. protected void service(HttpServletRequest req, HttpServletResponse resp)//判断请求方式是什么,并且进行相应的方法调用  
    16.      throws ServletException, IOException{  
    17.      long lastModified;  
    18.      String method = req.getMethod();  
    19.      if (method.equals("GET")) {  
    20.        lastModified = getLastModified(req);  
    21.      if (lastModified == -1L){  
    22.         doGet(req, resp);  
    23.      } else {  
    24.         long ifModifiedSince = req.getDateHeader("If-Modified-Since");  
    25.         if (ifModifiedSince < lastModified / 1000L * 1000L){  
    26.           maybeSetLastModified(resp, lastModified);  
    27.            doGet(req, resp);  
    28.         } else {  
    29.            resp.setStatus(304);  
    30.          }  
    31.        }  
    32.      }  
    33.     else if (method.equals("HEAD")) {  
    34.       lastModified = getLastModified(req);  
    35.       maybeSetLastModified(resp, lastModified);  
    36.      doHead(req, resp);  
    37.      }  
    38.    else if (method.equals("POST")) {  
    39.       doPost(req, resp);  
    40.      }  
    41.      else if (method.equals("PUT")) {  
    42.        doPut(req, resp);  
    43.      }  
    44.     else if (method.equals("DELETE")) {  
    45.       doDelete(req, resp);  
    46.      }  
    47.      else if (method.equals("OPTIONS")) {  
    48.       doOptions(req, resp);  
    49.      }  
    50.     else if (method.equals("TRACE")) {  
    51.        doTrace(req, resp);  
    52.      }  
    53.      else{  
    54.       String errMsg = lStrings.getString("http.method_not_implemented");  
    55.        Object[] errArgs = new Object[1];  
    56.        errArgs[0] = method;  
    57.       errMsg = MessageFormat.format(errMsg, errArgs);  
    58.        resp.sendError(501, errMsg);  
    59.      }  
    60.    }  

    这也就是我们平时在开发时用的最多的。

    [java]  view plain copy print ?
    1. package cn.xxc.servletday1;  
    2.   
    3. import java.io.IOException;  
    4.   
    5. import javax.servlet.ServletException;  
    6. import javax.servlet.http.HttpServlet;  
    7. import javax.servlet.http.HttpServletRequest;  
    8. import javax.servlet.http.HttpServletResponse;  
    9.   
    10. public class FirstServlet extends HttpServlet {  
    11.   
    12.     @Override  
    13.     protected void doGet(HttpServletRequest req, HttpServletResponse resp)  
    14.             throws ServletException, IOException {  
    15.         // TODO Auto-generated method stub  
    16.         super.doGet(req, resp);  
    17.     }  
    18.   
    19.     @Override  
    20.     protected void doPost(HttpServletRequest req, HttpServletResponse resp)  
    21.             throws ServletException, IOException {  
    22.         // TODO Auto-generated method stub  
    23.         super.doPost(req, resp);  
    24.     }  
    25.       
    26.   
    27. }  


    Response详解:

    1.首先要明确一点,确切的来说并不是response将服务器的响应送给了客户端,而是web容器将response里的内容取出后,生成响应的网页返回给客户端。

    2.状态码详解:

     voidsetStatus(int sc) 
              Sets the status code for this response.   设置状态码,但是有可能数字记不住,这时可以用静态常量来表示  例如HttpServletResponse.SC_BAD_REQUEST  表示404的意思
     voidsetStatus(int sc, java.lang.String sm)
              Deprecated. As of version 2.1, due to ambiguous meaning of the message parameter. To set a status code usesetStatus(int), to send an error with a description usesendError(int, String). Sets the status code and message for this response.过时设置状态码,同时生成状态码的message信息,设置message信息的时候不要忘记在前面加response.setCharacterEncoding("UTF-8");否则乱码如下图:

    voidsendError(int sc) 
              Sends an error response to the client using the specified status code and clearing the buffer.//设置状态码,而且清空下面写在response里的内容,返回给浏览器与状态码对应的结果页面,无论这个方法写在setStatus前还是后,都是此方法生效



    以下3种方式都是设置服务器相应数据的长度。

    [java]  view plain copy print ?
    1. response.setHeader("Content-Length""6");  
    2. response.setIntHeader("Content-Type"6);  
    3. response.setContentLength(6);  

    例如:总共返回3个字节,但是消息头却说有6个字节,这时浏览器的进度条就一直会处于等待状态。但最后进度条还是会读完,原因是服务器和浏览器建立的时间超过限定时间就和浏览器断开连接了。

    [java]  view plain copy print ?
    1. response.setHeader("Content-Length""6");  
    2. response.getOutputStream().write("aaa".getBytes());  
    问:为何消息头写的是5个字节,送回的数据是3个字节,进度条还是和正常一样无需等待就能显示?

    答:因为aaa后还有2个字节:\r\n。

    [java]  view plain copy print ?
    1. response.setContentLength(5);  
    2. response.getOutputStream().write("aaa".getBytes());  


    页面编码:

    默认:

    [java]  view plain copy print ?
    1. response.setHeader("Content-Type""text/html");//告诉浏览器服务器响应的数据要以字符显示(默认为上次在浏览器设置的编码形式)  
    2. response.getOutputStream().write("哈哈哈".getBytes());//响应的数据,以gbk(默认)编码成二进制数据送给浏览器  
    设置:

    [java]  view plain copy print ?
    1. response.setHeader("Content-Type""text/html;charset=utf-8");//设置浏览器用UTF-8编码来显示接收到的二进制数据  
    2. response.getOutputStream().write("哈哈哈".getBytes("utf-8"));//送给浏览器的二进制数据以UTF-8来进行编码  

    geiWriter:

    [java]  view plain copy print ?
    1. response.setHeader("Content-Type""text/html");//告诉浏览器服务器响应的数据要以字符显示(编码默认为gbk)  
    2. response.getWriter().println("好久不见");//这个操作省略了字符编码操作,根据上面设置的编码来确定用什么码来进行二进制编码,如果上面没写,则为ISO-8859-1  

    问:为何getWriter()不是默认GBK编码?

    答:getWriter()是tomcat的方法,它是按照tomcat默认编码iso-8859-1进行编码的,而getBytes()是JVM的方法,他默认是按照操作系统的编码。

    [java]  view plain copy print ?
    1. response.setHeader("Content-Type""text/html;charset=utf-8");//下面这两句和第一句是同一个意思  
    2. response.setContentType("text/html");  
    3. response.setCharacterEncoding("UTF-8");  

    设置网页不缓存的3个消息头:

    [java]  view plain copy print ?
    1. response.setDateHeader("Expires"0);  
    2. response.setHeader("Cache-Control""no-cache");  
    3. response.setHeader("Pragma""no-cache");  

    由于HTML页面是静态页面不能动态生成,所以HTML页面的编码采用如下格式定义:

    http-equiv表示等同于哪个消息头的意思 content表示消息头的值

    [html]  view plain copy print ?
    1. <meta http-equiv="Content-Type" content="text/html;charset=gbk">  

    如下例子可以证明:html加载页面的时候是先加载所有meta标签后,然后再加载正文的。

    [html]  view plain copy print ?
    1. <!DOCTYPE html>  
    2. <html>  
    3.   <head>  
    4.     <title>gbk.html</title>  
    5.       
    6.     <meta http-equiv="keywords" content="keyword1,keyword2,keyword3">  
    7.     <meta http-equiv="description" content="this is my page">  
    8.   </head>  
    9.     
    10.   <body>  
    11.       哈哈哈哈<br>   <!--依旧不显示乱码-->  
    12.   </body>  
    13.     <meta http-equiv="Content-Type" content="text/html;charset=gbk"><!--meta标签在下面也是有效的,meta会先于被加载-->  
    14. </html>  

    模拟自动刷新的消息头:

    [html]  view plain copy print ?
    1. <meta http-equiv="Refresh" content="3">  


    静态网页的取消缓存:(但是发现经过多次刷新后还是进行了缓存,状态码304)

    [html]  view plain copy print ?
    1. <meta http-equiv="Expires" content="0">  
    2. <meta http-equiv="Cache-Control" content="no-cache">  
    3. <meta http-equiv="Pragma" content="no-cache">  

    用于文件下载的两个消息头:

    [html]  view plain copy print ?
    1. response.setContentType("application/octet-stream");//告诉浏览器服务器返回的是二进制数据  
    2. response.setHeader("Content-Disposition", "attachment;filename="+URLEncoder.encode("皮卡丘.txt","UTF-8"));//如果URL里有中文必须进行URL的编码  

    注意:

    往respons里写数据的时候,response并不是马上把写入的数据交给服务器处理的,而是先写到response的缓冲区里的。




    Request:

    注意:

    jsp中代码

    [html]  view plain copy print ?
    1. <form action="servlet/ThirdServlet?userName=1&passWord=2" method="post">  
    2.          姓名<input type="text" name="uesrName"><br>  
    3.         密码<input type="text" name="passWord"><br>  
    4.         <input type="submit" value="提交">  
    5. </form>  
    servlet中代码

    [java]  view plain copy print ?
    1. public void doPost(HttpServletRequest request, HttpServletResponse response)  
    2.             throws ServletException, IOException {  
    3.         String userName = request.getParameter("userName");  
    4.         String passWord = request.getParameter("passWord");  
    5.         response.getWriter().println("userName --->"+userName);  
    6.         response.getWriter().println("passWord---->"+passWord);  
    7. }  
    经过测试发现,get请求时候,组件里的值会覆盖url后的参数,而post既可以获取url后面的参数的值也可以获取组件里的值


    关于浏览器发送给服务器乱码问题:

    在servlet中一直有这么一个疑问:

    request.setCharacterEncoding("UTF-8");这个方法里的参数到底是GBK还是UTF-8或者是别的什么编码。

    经过HTTP协议的学习后,势必有这么一个疑问,response送给浏览器显示网页的时候,会告诉浏览器要用什么码来显示网页,那么浏览器传递数据给服务器的时候,是否也有这么一个消息头来告诉服务器应该以什么码来解码浏览器送给服务器的中文数据呢?事实上,浏览器没有这么一个消息头送给服务器。也就是说

    [java]  view plain copy print ?
    1. System.out.println(request.getCharacterEncoding());  
    这句话的打印结果是Null。

    那么,我们该如何去设置request.setCharacterEncoding("UTF-8")方法里的参数呢?

    既然,我们不能获取浏览器是用什么码编码,那就规定好浏览器在进行中文数据编码的时候用什么码来编码的。

    (浏览器将中文数据是按什么码进行编码的,主要看浏览器当前显示网页的编码是什么码。例如IE可以右键--->编码进行查看和设置。)

    这样我们就可以把request.setCharacterEncoding("UTF-8");方法里的参数写成规定的编码。来解决问题了。



    request.setCharacterEncoding("UTF-8");只针对post提交有效,因为这句话针对的是请求体里的内容解码。

    对URL后面的中文参数是起不到解决乱码的作用,即get方式提交时,此方法无效。

    那么改怎么办呢?

    1.在tomcat的conf文件夹下的server.xml文件的改tomcat端口的标签里增加如下属性,表示经过URL编码的的中文都用UTF-8来解码。

    [html]  view plain copy print ?
    1. <Connector port="9090" protocol="HTTP/1.1"   
    2.               connectionTimeout="20000"   
    3.               redirectPort="8443" <span style="font-family: Arial, Helvetica, sans-serif;">URIEncoding="UTF-8"</span>/>  

    2.在tomcat的conf文件夹下的server.xml文件的改tomcat端口的标签里增加如下属性,表示是否用post处理中文的方式来处理get的中文乱码问题。这样改还不够,需要在post方法里写出用什么码解码。也就是说需要两步!

    [html]  view plain copy print ?
    1. <Connector port="9090" protocol="HTTP/1.1"   
    2.               connectionTimeout="20000"   
    3.               redirectPort="8443" useBodyEncodingForURI="true"/>  


    [java]  view plain copy print ?
    1. public void doPost(HttpServletRequest request, HttpServletResponse response)  
    2.             throws ServletException, IOException {  
    3.         request.setCharacterEncoding("UTF-8");  
    4. }  


    3.但是以上两种解决get请求的中文乱码问题的方式仅限于tomcat服务器,如果是别的web服务器该怎么解决呢?

    [java]  view plain copy print ?
    1. String userName = request.getParameter("userName");  
    2. userName = new String(userName.getBytes("iso-8859-1"),"UTF-8");  


    request.getRequestDispatcher().include(request, response)和request.getRequestDispatcher().forward(request, response)方法的区别:

    这个方法是跳转到一个页面上,并且把request和response都带去下个页面。

    [java]  view plain copy print ?
    1. request.getRequestDispatcher("/WEB-INF/success.jsp").forward(request, response);  

    但是如下例子:

    servlet代码

    [java]  view plain copy print ?
    1. response.setCharacterEncoding("UTF-8");  
    2. response.getWriter().println("跳转前...");  
    3. request.getRequestDispatcher("/index.jsp").forward(request, response);  
    4. response.getWriter().println("跳转后...");  
    如果用request.getRequestDispatcher().forward(request, response);只能显示index.jsp页面的内容,不能显示response用write方法往缓冲区里写的内容。

    原因:在进行forward跳转的时候,会将writer往缓冲区里写的内容全部清空。


    [java]  view plain copy print ?
    1. response.setCharacterEncoding("UTF-8");  
    2. response.getWriter().println("跳转前...");  
    3. request.getRequestDispatcher("/index.jsp").include(request, response);  
    4. response.getWriter().println("跳转后...");  
    如果用
    request.getRequestDispatcher("/index.jsp").include(request, response);则不会清空write往缓冲区里写的内容。即,可以显示   跳转前和跳转后字样。

    但是经过测试发现,如果用request.getRequestDispatcher("/index.jsp").include(request, response);进行页面的跳转,Chrome和Firefox会把index.jsp页面的源码原封不懂的显示给浏览器,而IE可以正确显示index,jso里body里的部分。


    当使用request.getRequestDispatcher("/index.jsp").include(request, response);被引用的index.jsp页面中有中文字符,这时index.jsp页面里的page指令都是无效的。所以会出现乱码。

    因为这时是引用的,servlet只引用了jsp中的内容,那么用什么编码显示被引用的页面是由引用方来决定的。所以,为了防止出现乱码,需要在servlet里加一句:response.setCharacterEncoding("UTF-8");


    展开全文
  • 关闭钩子

    2021-02-09 20:46:35
    文章目录前言一、关闭钩子二、简单案例三、Tomcat中的钩子方法案例总结 前言 在很多实际应用环境中,当用户关闭了应用程序时,需要做一些善后清理工作,但问题是,用户有时并不会按照推荐的方法关闭应用程序,很有...


    前言

    在很多实际应用环境中,当用户关闭了应用程序时,需要做一些善后清理工作,但问题是,用户有时并不会按照推荐的方法关闭应用程序,很有可能不会做清理工作。例如,在Tomcat的部署应用当中,通过实例化一个Server对象来启动servlet容器,调用其start()方法,然后逐个调用组件的start方法。正常情况下,为了让Server对象能够关闭这些已经启动的组件,应该通过发送关闭命令的方式。如果你只是简单的突然退出,例如在应用程序运行过程中关闭控制台,可能会发生一些意想不到的事情

    幸运的是,Java为程序员提供了一种优雅的方法可以再关闭过程中执行一些代码,这样就能确保那些负责善后处理的代码肯定能够执行。本章将展示如何使用关闭钩子来确保清理代码总是能够执行,无论用户如何终止应用程序。


    一、关闭钩子

    在Java中,虚拟机会对两类事件进行响应,然后执行关闭操作:

    • 当调用System.exit方法或者程序的最后一个非守护线程退出时,应用程序可以正常退出;
    • 用户突然强制虚拟机中断运行,例如用户按CTRL+C快捷键或者在未关闭Java程序的情况下,从系统中退出。

    幸运的是,虚拟机在执行关闭操作时,会经过以下两个阶段:

    1. 虚拟机启动所有已经注册的关闭钩子,如果有的话,关闭钩子是先前已经通过Runtime类注册的线程,所有的关闭钩子会并发执行,直到完成任务。
    2. 虚拟机根据情况调用所有没有被调用过的终结器(finalizer).

    本章重点说明第一个阶段,因为该阶段允许程序员告诉虚拟机在应用程序中执行一些清理代码,关闭钩子很简单,只是一个java.lang.Thread类的一个子类的实例,创建关闭钩子很简单:

    • 创建Thread类的一个子类
    • 实现run方法,当应用程序(正常或突然)关闭时,会调用此方法
    • 在应用程序中,实例化关闭钩子类
    • 使用当前Runtime类的addShutdownHook方法注册关闭钩子.

    也许你已经注意到了,不需要像启动其他线程一样调用关闭钩子的start方法,虚拟机会在它运行其关闭流程时启动并执行关闭钩子。

    二、简单案例

    定义一个简单的ShutdownHookDemo类和一个Thread类(ShutdownHook类)的子类。注意,ShutdownHook类的run方法只是简单地将字符串"Shutting down"输出到控制台上,但是可以插入在应用程序关闭之前执行的任何代码。

    import java.io.IOException;
    
    public class ShutdownHookDemo {
    
        public void start() {
            System.out.println("Demo");
            ShutdownHook shutdownHook = new ShutdownHook();
            Runtime.getRuntime().addShutdownHook(shutdownHook);
        }
    
        public static void main(String[] args) {
            ShutdownHookDemo shutdownHookDemo = new ShutdownHookDemo();
            shutdownHookDemo.start();
            try {
                System.in.read();
            } catch (IOException e) {
            }
        }
    
        class ShutdownHook extends Thread {
            @Override
            public void run() {
                System.out.println("Shutting down");
            }
        }
    }
    

    在实例化ShutdownHookDemo类后,main方法会调用start方法。start方法会创建一个关闭钩子,并通过当前Runtime注册它。然后,应用程序会等待用户输入,当用户按下Enter键之后,应用程序会退出,但是,虚拟机会执行关闭钩子,最后在控制台输出字符串"Shutting down"。
    在这里插入图片描述

    三、Tomcat中的钩子方法案例

    正如你想的一样,Tomcat也是通过关闭钩子来完成退出流程的,在org.apache.catalina.startup.Catalina类中,可以找到这样的代码。Catalina类负责启动管理其他组件的Server对象。一个名为CatalinaShutdownHook的内部类继承自Thread类,提供了run方法的实现,它会调用Server对象的stop方法,完成关闭操作。如下所示

    /**
     * Shutdown hook which will perform a clean shutdown of Catalina if needed.
     */
    protected class CatalinaShutdownHook extends Thread {
    
        @Override
        public void run() {
            try {
                if (getServer() != null) {
                    Catalina.this.stop();
                }
            } catch (Throwable ex) {
                ExceptionUtils.handleThrowable(ex);
                log.error(sm.getString("catalina.shutdownHookFail"), ex);
            } finally {
                // If JULI is used, shut JULI down *after* the server shuts down
                // so log messages aren't lost
                LogManager logManager = LogManager.getLogManager();
                if (logManager instanceof ClassLoaderLogManager) {
                    ((ClassLoaderLogManager) logManager).shutdown();
                }
            }
        }
    }
    

    在Catalina实例启动时,会实例化关闭钩子,并在一个阶段将其添加到Runtime类中。
    在这里插入图片描述
    注册了关闭钩子,但是也要注意如果是正常调用stop方法的情况下需要首先通过java.lang.Runtime#removeShutdownHook方法移除钩子以免触发两次的关闭操作。

    /**
     * Stop an existing server instance.
     */
    public void stop() {
    
        try {
            // Remove the ShutdownHook first so that server.stop()
            // doesn't get invoked twice
            if (useShutdownHook) {
                Runtime.getRuntime().removeShutdownHook(shutdownHook);
    
                // If JULI is being used, re-enable JULI's shutdown to ensure
                // log messages are not lost
                LogManager logManager = LogManager.getLogManager();
                if (logManager instanceof ClassLoaderLogManager) {
                    ((ClassLoaderLogManager) logManager).setUseShutdownHook(
                            true);
                }
            }
        } catch (Throwable t) {
            ExceptionUtils.handleThrowable(t);
            // This will fail on JDK 1.2. Ignoring, as Tomcat can run
            // fine without the shutdown hook.
        }
    
        // Shut down the server
        try {
            Server s = getServer();
            LifecycleState state = s.getState();
            if (LifecycleState.STOPPING_PREP.compareTo(state) <= 0
                    && LifecycleState.DESTROYED.compareTo(state) >= 0) {
                // Nothing to do. stop() was already called
            } else {
                s.stop();
                s.destroy();
            }
        } catch (LifecycleException e) {
            log.error(sm.getString("catalina.stopError"), e);
        }
    
    }
    

    总结

    有时候,应用程序在关闭之前应该执行一些代码清理工作,但是,你不能假设用户总是正常退出。本章介绍的关闭钩子提供了一种解决方案,确保无论用户如何关闭应用程序,清理代码总是能够得到执行。

    展开全文
  • 生命周期有其固定的一些生命动作,也就是方法,即俗称的钩子函数。到哪个点儿,就执行哪个方法。 比如初始化时,执行init()方法,运行时执行service()方法,销毁时执行destroy()方法等。 注意,servlet在开发时,...

    1 Servlet生命周期的概念说明:

    Servlet生命周期指一个Servlet创建到销毁的过程,我们将这个过程称之为"Servlet生命周期"。
    生命周期有其固定的一些生命动作,也就是方法,即俗称的钩子函数。到哪个点儿,就执行哪个方法。
    比如初始化时,执行init()方法,运行时执行service()方法,销毁时执行destroy()方法等。

    注意,servlet在开发时,我们写的是类。
    而在运行时,我们用的是servlet的对象,也就是组件。

    2 每一个Servlet都拥有以下处理过程

    Servlet初始化后调用init()方法
    Servlet调用service()方法来处理客户端的请求
    Servlet销毁前调用destroy() 方法
    最后Servlet是由JVM的垃圾回收器进行垃圾回收的

    3 init()方法

    见名估计,就是初始化方法。事先执行,只执行一次。
    init()方法在第一次创建Servlet时被调用后续用户调用此Servlet时,无需再次运行init()方法。
    当用户第一次调用Servlet对应URL时,Servlet被创建,我们也可以指定Servlet在服务器中第一次启动时加载
    当用户调用一个Servlet时,就会创建一个Servlet实例,容器创建实例的过程,即new一个对象的过程,可以使用servlet的构造器去检验!!!
    而servlet的服务是多线程的:每一个用户请求都会产生一个新的线程,适当的时候移交给 doGet 或 doPost 方法
    init() 方法简单地创建或加载一些数据,这些数据将被用于 Servlet 的整个生命周期

    例:init 方法
    public void init() throws ServletException {
    // 初始化代码…
    }

    4 service()方法

    service() 方法是执行实际任务的主要方法
    Servlet容器(即Web 服务器)调用service()方法来处理来自客户端(浏览器)的请求
    将格式化数据返回给客户端
    当服务器收到Servlet请求时,
    服务器会产生一个新的线程并调用服务

    service() 方法中会检查http的请求类型(GET、POST、PUT、DELETE等),
    并调用相应的doGet、doPost、doPut,doDelete 等方法
    例:
    service方法定义
    public void service(ServletRequest request,
    ServletResponse response)
    throws ServletException, IOException{
    }
    service()方法由web容器调用
    service 方法然后调用doGet,doPost,doPut,doDelete等方法
    所以我们只需将相应的代码放入doGet()及doPost()方法中
    doGet()方法
    public void doGet(HttpServletRequest request,
    HttpServletResponse response)
    throws ServletException, IOException {
    // Servlet 代码
    }

    建议阅读HttpServlet类的源码,就可以发现
    service方法有两个,一个是保护的,一个公共的
    公共的对外服务方法
    实现服务的过程中,它会调用保护的方法
    在保护的方法中,会识别请求的参数,按请求方式,调用不同的服务的具体方法,如doGet,doPost等。
    

    doPost()方法
    public void doPost(HttpServletRequest request,
    HttpServletResponse response)
    throws ServletException, IOException {
    // Servlet 代码
    }

    5 destroy()方法

    destroy() 方法只会被调用一次
    在Servlet生命周期结束时被调用
    destroy() 方法可以让您的Servlet 关闭数据库连接

    停止后台线程
    把 Cookie 列表或点击计数器写入到磁盘
    并执行其他类似的清理活动
    servlet对象被标记为垃圾回收
    destroy方法定义如下所示:
    public void destroy() {
    // 终止化代码…
    }

    展开全文
  • 创建servlet层VerifyCodeServlet类,用于每次访问该servlet时调用工具类生成验证码图片并将图片输出到页面,同时将获取到的验证码通过servletContext对象共享数据通过另一个servlet将验证码响应到页面中 package ...
  • 嵌入式Servlet容器自动配置、启动、配置原理
  • servlet详解

    2017-08-13 17:50:34
    Servlet简介 Servlet是服务器端的重要组件,直译为服务端的小程序,它属于动态资源,用来处理请求,服务器接收到请求后会调用Servlet来处理请求。 Servlet的主要作用 接收请求 处理请求 完成响应 例如: 当...
  • 10 Servlet

    2022-08-11 23:50:17
    Servlet
  • [toc]前言Spring 提供了非常多的扩展接口,官方将这些接口称之为钩子,这些钩子会在特定的时间被回调,以此来增强 Spring 功能,众多优秀的框架也是通过扩展这些接口,来实现自身特定的功能,如 SpringBoot、mybatis...
  • 本文只强调使用gitblit内置的钩子,与使用git hook和WebHook情况有所不同一、先普及一下gitblit是使用java语言开发的一个git管理工具,其后台使用的是servlet配置作为网页服务器,引用一句话:Gitblit 是一个纯 Java...
  • 有些时候我们需要在 Spring Boot Servlet Web 应用中声明一些自定义的 Servlet Filter 来处理一些逻辑。比如简单的权限系统、请求头过滤、防止 XSS 攻击等。本篇将讲解如何在 Spring Boot 应用中声明自定义 Servlet ...
  • 网络钩子servlet 将此 servlet 部署到您的 tomcat 上,以便在 git 获得推送时调用本地脚本。 在您的 tomcat 上部署 war 文件。 创建脚本/opt/webhook/webhook.sh,内容类似于: #!/bin/bash echo 'This is a ...
  • ServletConfig接口也位于javax.servlet包下,包含 servlet 的配置和初始化参数,在Servlet初始化时,传递给init方法。 ServletContext接口也位于javax.servlet包下,ServletContext官方叫servlet上下文。服务器会为...
  • Spring是我们经常使用的一个框架,它功能之一是提供了我们管理bean对象的手段,而且它提供了很多钩子方法给我们使用。什么是钩子方法呢?钩子方法就是:在bean的生命周期之中,经历了一系列的过程之中,Spring留给...
  • Servlet生命周期详解

    千次阅读 2018-10-06 16:20:56
    Servlet程序时运行在服务器端的java程序,生命周期收到web容器的控制。 生命周期有5部分:加载,初始化,服务,销毁,卸载 其生命周期都可以在HttpServlet和GenericServlet中找到对应的方法。 1、加载...
  • servlet生命周期详解

    2020-08-21 11:08:05
    Web容器负责加载Servlet,当web容器启东时或者在第一次使用这个Servlet的时候,容器会负责创建Servlet实例,但是用户必须通过web.xml指定Servlet的位置,成功加载后,Web容器会通过反射的方式对Servlet进行实例化。...
  • liferay-change-password-via-rest Liferay 钩子在用户更改密码时调用 REST 服务
  • 我最开始写的是SpringMVC的开始案例,从SpringMvc的请求原理,写着写着,就写到了Servlet的生命周期了,感觉越写越底层啊。主要掌握Servlet的生命周期,以及HttpServler与Servlet的关系
  • 1、实例、组件通过new Vue() 创建出来之后会初始化事件和生命周期,然后就会执行beforeCreate钩子函数,这个时候,数据还没有挂载呢,只是一个空壳,无法访问到数据和真实的dom,一般不做操作 2、挂载数据,绑定事件...
  • #servlet容器的修改 server.port=80888 在配置文件中修改服务器端口,配置文件绑定的配置类是 @ConfigurationProperties(prefix = "server", ignoreUnknownFields = true) public class ServerProperties ...
  • Servlet实现日志管理

    千次阅读 2017-08-27 23:08:19
    //本文主要实现学员日志管理功能,表单以及前端等样式代码省略,主要servlet方法实现的功能的如下: package com.softeem.dao; import java.util.List; public interface BaseDAO { public boolean save(T t);...
  • Servlet基础知识

    2017-08-10 19:58:35
    Servlet 1.Servlet简介 Servlet是服务器端的重要组件,直译为服务端的小程序,它属于动态资源,用来处理请求,服务器接收到请求后会调用Servlet来处理请求。 Servlet的主要作用 接收请求 处理请求 完成...
  • Servlet详解

    2017-08-18 08:42:00
    1. Servlet简介 l Servlet是服务器端的重要组件,直译为服务端的小程序,它属于动态资源,用来处理请求,服务器接收到请求后会调用Servlet来处理请求。 l Servlet的主要作用 n 接收请求 n 处理请求 n 完成响应 ...
  • 再续Servlet

    2018-12-03 18:46:34
    Servlet 1. 概述 Servlet 是运行在 Web 服务器中的小型 Java 程序。Servlet 通常通过 HTTP(超文本传输协议)接收和响应来自 Web 客户端的请求。 要实现此接口,可以编写一个扩展 javax.servlet.GenericServlet的...
  • vue生命周期钩子函数

    2022-06-27 18:47:51
    <div>{{name}}</div> beforeCreated:我们在用Vue时都要进行实例化,因此,该函数就是在Vue实例化时调用,也可以将他理解为初始化函数比较方便一点,在Vue1.0时,这个函数的名字就是init。...
  • servlet基础浅谈

    2019-01-02 00:47:09
    在整个应用的启动、运行、销毁时,servlet技术对外暴露了什么样的事件钩子,让开发者可以干预利用这些事件? servlet、filter、listener如何通过配置让servlet容器来感知并利用? spring是如何基于这些知识点构建起...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 4,926
精华内容 1,970
关键字:

servlet钩子