zoukankan      html  css  js  c++  java
  • Servlet中几个常用方法的推衍

      JavaWeb开发中,Servlet是重要的一环,常用于处理逻辑事物。现在比较习惯用编辑器直接新建一个Servlet出来,但是对于初学者,这样的方式并不能理解到它从最原始的形态到现在的演变,本文就此做一个简单的推演,从Servlet的生命周期开始,到现在比较常用的做法,搭建一个桥梁,让初学者可以很容易看懂为什么要这么做。

      新建一个Maven工程,引入必要依赖:

    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>servlet-api</artifactId>
        <version>2.5</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>javax.servlet</groupId>
        <artifactId>jsp-api</artifactId>
        <version>2.0</version>
        <scope>provided</scope>
    </dependency>

    在web.xml中配置好<Servlet/>以及<Servlet-mapping/>

    <servlet>
        <servlet-name>OriginalServlet</servlet-name>
        <servlet-class>com.test.OriginalServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>OriginalServlet</servlet-name>
        <url-pattern>/OriginalServlet</url-pattern>
    </servlet-mapping>

    并在类中,实现Servlet接口,实现其中的几个方法:

    import java.io.IOException;
    import javax.servlet.Servlet;
    import javax.servlet.ServletConfig;
    import javax.servlet.ServletException;
    import javax.servlet.ServletRequest;
    import javax.servlet.ServletResponse;
    
    /**
     * Servlet implementation class OriginalServlet
     */
    public class OriginalServlet implements Servlet {
    
        /**
         * Default constructor.
         */
        public OriginalServlet() {
            // TODO Auto-generated constructor stub
        }
    
        /**
         * @see Servlet#init(ServletConfig)
         */
        public void init(ServletConfig config) throws ServletException {
            // TODO Auto-generated method stub
        }
    
        /**
         * @see Servlet#destroy()
         */
        public void destroy() {
            // TODO Auto-generated method stub
        }
    
        /**
         * @see Servlet#service(ServletRequest request, ServletResponse response)
         */
        public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException {
            // TODO Auto-generated method stub
        }
    
        /**
         * @see Servlet#getServletConfig()
         */
        public ServletConfig getServletConfig() {
            // TODO Auto-generated method stub
            return null;
        }
    
        /**
         * @see Servlet#getServletInfo()
         */
        public String getServletInfo() {
            // TODO Auto-generated method stub
            return null;
        }
    }

      诠释Servlet生命周期时,一定离不开三个重要的方法:

    • 一个init(ServletConfig),表示初始化方法。默认情况下,是第一次调用该Servlet之前执行,如果需要它在服务器启动时执行,只需要在web.xml中配置<load-on-startup/>参数,其中的数字越小,被加载的优先级越高;

    ServletConfig表示servlet配置信息的封装对象,其中有几个比较重要的方法:

    getServletName()   --  获得<servlet/><servlet-name/>的名称
    getInitParameter(name)   --  获得初始化参数
    getInitParameterNames()  --  获得所有的初始化参数(迭代器前身)
    getServletContext()  --  详细内容见后部分

    • 第二个是service(ServletRequest,ServletResponse)表示servlet执行方法,每一次请求将会执行一次;

    tomcat作为服务器时,每次访问到该Servlet时,就会调用该service方法,控制台输出该request与response参数,可以发现输出如下:

    org.apache.catalina.connector.RequestFacade@5caf2b5
    org.apache.catalina.connector.ResponseFacade@624641db

    翻看源码,可以看出,这两个对象所对应的类,其实所实现的是HttpServletRequest与HttpServletResponse接口,所以:

    HttpServletRequest httpServletRequest = (HttpServletRequest)request;
    HttpServletResponse httpServletResponse = (HttpServletResponse)response;
    • 第三个是destroy()表示销毁方法,会在服务器正常关闭时执行一次。

    ------------------------------------------------------------------------------------->

      有了上述的接口的几个方法,我们会想到,如何在真正使用的时候,将它最简化。对于init(ServletConfig),destroy()等不常用到的方法,我们可以用一个基础类实现Servlet接口,之后所有的servlet类继承该基础类,需要用到某个方法时,覆写实现即可。

      以下几点都是基于如何将后续常用的Servlet最简化而进行的基础工作:

    • 将service方法用abstract修饰,使这个方法成为子类必须实现的方法
    • 基础类中的init(ServletConfig)方法拥有的配置信息对象参数,要用一种简洁方式提供给子类,所以用私有属性获得该参数,并提供get方法返回;进一步地,如果子类中需要用到该参数,那么会getServletConfig().getServletName()获取,于是我们让基础类实现ServletConfig这个接口,提供几个获取重要参数的方法,并在方法体中返回getServletConfig().getXXX(),这样,子类中就可以直接调用这些方法获取到相应的参数
    • 避免出现子类的init(ServletConfig)方法忘记执行super(ServletConfig)而出现NullPointerException,所以在基础类中的init(ServletConfig)方法调用一个本地的init()方法,子类如果需要,就覆盖init()方法,保证初始化顺利地进行
    package javax.servlet;
    
    import java.io.IOException;
    import java.util.Enumeration;
    import java.util.ResourceBundle;
    
    public abstract class GenericServlet 
        implements Servlet, ServletConfig, java.io.Serializable
    {
        private static final String LSTRING_FILE = "javax.servlet.LocalStrings";
        private static ResourceBundle lStrings =
            ResourceBundle.getBundle(LSTRING_FILE);
    
        private transient ServletConfig config;
    
    
        public GenericServlet() { }
    
    
        public void destroy() {
        }
    
        public String getInitParameter(String name) {
            ServletConfig sc = getServletConfig();
            if (sc == null) {
                throw new IllegalStateException(
                    lStrings.getString("err.servlet_config_not_initialized"));
            }
    
            return sc.getInitParameter(name);
        }
    
        public Enumeration getInitParameterNames() {
            ServletConfig sc = getServletConfig();
            if (sc == null) {
                throw new IllegalStateException(
                    lStrings.getString("err.servlet_config_not_initialized"));
            }
    
            return sc.getInitParameterNames();
        }   
        
        public ServletConfig getServletConfig() {
        return config;
        }
    
        public ServletContext getServletContext() {
            ServletConfig sc = getServletConfig();
            if (sc == null) {
                throw new IllegalStateException(
                    lStrings.getString("err.servlet_config_not_initialized"));
            }
    
            return sc.getServletContext();
        }
        
        public String getServletInfo() {
        return "";
        }
    
        public void init(ServletConfig config) throws ServletException {
        this.config = config;
        this.init();
        }
       
        public void init() throws ServletException {
    
        }
             
        public void log(String msg) {
        getServletContext().log(getServletName() + ": "+ msg);
        }
          
        public void log(String message, Throwable t) {
        getServletContext().log(getServletName() + ": " + message, t);
        }
        
        public abstract void service(ServletRequest req, ServletResponse res)
        throws ServletException, IOException;
        
        public String getServletName() {
            ServletConfig sc = getServletConfig();
            if (sc == null) {
                throw new IllegalStateException(
                    lStrings.getString("err.servlet_config_not_initialized"));
            }
            return sc.getServletName();
        }
    }

    ------------------------------------------------------------------------------------->

      实现http协议

      之前已经看到,在service方法中可以转为HttpServletRequest与HttpServletResponse两个接口,从而支持http相关的服务。但每次都做这种强转还是相当麻烦的,所以,我们做如下处理:

    HttpServletRequest httpServletRequest = (HttpServletRequest) req;
    HttpServletResponse httpServletResponse = (HttpServletResponse) res;

    所以,我们需要一个符合http,使用起来相对简便的基础类来作为常用servlet的父类,首先做如下改造:

    public class MyHttpServlet extends GenericServlet {
        private static final long serialVersionUID = 1L;
    
        @Override
        public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException {
            HttpServletRequest httpServletRequest = (HttpServletRequest) req;
            HttpServletResponse httpServletResponse = (HttpServletResponse) res;
            service(httpServletRequest,httpServletResponse);
        }
    
        public void service(HttpServletRequest request, HttpServletResponse response) {
            
        }
    }

    这样在基类中可以比较方便地使用改造之后的方法,其参数就直接是HttpServletRequest与HttpServletResponse,不用做额外地转换。在service中,可以根据request的访问方法(GET,POST,PUT,DELETE...)对其进行相应的处理,从而衍生出doGet(HttpServletRequest request, HttpServletResponse response),doPost(HttpServletRequest request, HttpServletResponse response)等常用方法。这里可以看看官方给出的HttpServlet源码:

    package javax.servlet.http;
    
    import java.io.IOException;
    import java.io.PrintWriter;
    import java.io.OutputStreamWriter;
    import java.io.UnsupportedEncodingException;
    import java.lang.reflect.Method;
    import java.text.MessageFormat;
    import java.util.Enumeration;
    import java.util.Locale;
    import java.util.ResourceBundle;
    
    import javax.servlet.GenericServlet;
    import javax.servlet.ServletException;
    import javax.servlet.ServletOutputStream;
    import javax.servlet.ServletRequest;
    import javax.servlet.ServletResponse;
    
    public abstract class HttpServlet extends GenericServlet
        implements java.io.Serializable
    {
        private static final String METHOD_DELETE = "DELETE";
        private static final String METHOD_HEAD = "HEAD";
        private static final String METHOD_GET = "GET";
        private static final String METHOD_OPTIONS = "OPTIONS";
        private static final String METHOD_POST = "POST";
        private static final String METHOD_PUT = "PUT";
        private static final String METHOD_TRACE = "TRACE";
    
        private static final String HEADER_IFMODSINCE = "If-Modified-Since";
        private static final String HEADER_LASTMOD = "Last-Modified";
        
        private static final String LSTRING_FILE =
        "javax.servlet.http.LocalStrings";
        private static ResourceBundle lStrings =
        ResourceBundle.getBundle(LSTRING_FILE);
    
        public HttpServlet() { }
     
        protected void doGet(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException
        {
        String protocol = req.getProtocol();
        String msg = lStrings.getString("http.method_get_not_supported");
        if (protocol.endsWith("1.1")) {
            resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
        } else {
            resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
        }
        }
    
    
        protected long getLastModified(HttpServletRequest req) {
        return -1;
        }
    
        protected void doHead(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException
        {
        NoBodyResponse response = new NoBodyResponse(resp);
        
        doGet(req, response);
        response.setContentLength();
        }
        
    
        protected void doPost(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException
        {
        String protocol = req.getProtocol();
        String msg = lStrings.getString("http.method_post_not_supported");
        if (protocol.endsWith("1.1")) {
            resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
        } else {
            resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
        }
        }
    
        protected void doPut(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException
        {
        String protocol = req.getProtocol();
        String msg = lStrings.getString("http.method_put_not_supported");
        if (protocol.endsWith("1.1")) {
            resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
        } else {
            resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
        }
        }
    
        protected void doDelete(HttpServletRequest req,
                    HttpServletResponse resp)
        throws ServletException, IOException
        {
        String protocol = req.getProtocol();
        String msg = lStrings.getString("http.method_delete_not_supported");
        if (protocol.endsWith("1.1")) {
            resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
        } else {
            resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
        }
        }
        
    
        private Method[] getAllDeclaredMethods(Class c) {
    
            if (c.equals(javax.servlet.http.HttpServlet.class)) {
                return null;
            }
    
            Method[] parentMethods = getAllDeclaredMethods(c.getSuperclass());
            Method[] thisMethods = c.getDeclaredMethods();
        
            if ((parentMethods != null) && (parentMethods.length > 0)) {
                Method[] allMethods =
                    new Method[parentMethods.length + thisMethods.length];
            System.arraycopy(parentMethods, 0, allMethods, 0,
                                 parentMethods.length);
            System.arraycopy(thisMethods, 0, allMethods, parentMethods.length,
                                 thisMethods.length);
    
            thisMethods = allMethods;
        }
    
        return thisMethods;
        }
       
        protected void doOptions(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException
        {
        Method[] methods = getAllDeclaredMethods(this.getClass());
        
        boolean ALLOW_GET = false;
        boolean ALLOW_HEAD = false;
        boolean ALLOW_POST = false;
        boolean ALLOW_PUT = false;
        boolean ALLOW_DELETE = false;
        boolean ALLOW_TRACE = true;
        boolean ALLOW_OPTIONS = true;
        
        for (int i=0; i<methods.length; i++) {
            Method m = methods[i];
            
            if (m.getName().equals("doGet")) {
            ALLOW_GET = true;
            ALLOW_HEAD = true;
            }
            if (m.getName().equals("doPost")) 
            ALLOW_POST = true;
            if (m.getName().equals("doPut"))
            ALLOW_PUT = true;
            if (m.getName().equals("doDelete"))
            ALLOW_DELETE = true;
            
        }
        
        String allow = null;
        if (ALLOW_GET)
            if (allow==null) allow=METHOD_GET;
        if (ALLOW_HEAD)
            if (allow==null) allow=METHOD_HEAD;
            else allow += ", " + METHOD_HEAD;
        if (ALLOW_POST)
            if (allow==null) allow=METHOD_POST;
            else allow += ", " + METHOD_POST;
        if (ALLOW_PUT)
            if (allow==null) allow=METHOD_PUT;
            else allow += ", " + METHOD_PUT;
        if (ALLOW_DELETE)
            if (allow==null) allow=METHOD_DELETE;
            else allow += ", " + METHOD_DELETE;
        if (ALLOW_TRACE)
            if (allow==null) allow=METHOD_TRACE;
            else allow += ", " + METHOD_TRACE;
        if (ALLOW_OPTIONS)
            if (allow==null) allow=METHOD_OPTIONS;
            else allow += ", " + METHOD_OPTIONS;
        
        resp.setHeader("Allow", allow);
        }
     
        protected void doTrace(HttpServletRequest req, HttpServletResponse resp) 
        throws ServletException, IOException
        {
        
        int responseLength;
        
        String CRLF = "
    ";
        String responseString = "TRACE "+ req.getRequestURI()+
            " " + req.getProtocol();
        
        Enumeration reqHeaderEnum = req.getHeaderNames();
        
        while( reqHeaderEnum.hasMoreElements() ) {
            String headerName = (String)reqHeaderEnum.nextElement();
            responseString += CRLF + headerName + ": " +
            req.getHeader(headerName); 
        }
        
        responseString += CRLF;
        
        responseLength = responseString.length();
        
        resp.setContentType("message/http");
        resp.setContentLength(responseLength);
        ServletOutputStream out = resp.getOutputStream();
        out.print(responseString);    
        out.close();
        return;
        }        
    
        protected void service(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException
        {
        String method = req.getMethod();
    
        if (method.equals(METHOD_GET)) {
            long lastModified = getLastModified(req);
            if (lastModified == -1) {
            // servlet doesn't support if-modified-since, no reason
            // to go through further expensive logic
            doGet(req, resp);
            } else {
            long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
            if (ifModifiedSince < (lastModified / 1000 * 1000)) {
                // If the servlet mod time is later, call doGet()
                        // Round down to the nearest second for a proper compare
                        // A ifModifiedSince of -1 will always be less
                maybeSetLastModified(resp, lastModified);
                doGet(req, resp);
            } else {
                resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
            }
            }
    
        } else if (method.equals(METHOD_HEAD)) {
            long lastModified = getLastModified(req);
            maybeSetLastModified(resp, lastModified);
            doHead(req, resp);
    
        } else if (method.equals(METHOD_POST)) {
            doPost(req, resp);
            
        } else if (method.equals(METHOD_PUT)) {
            doPut(req, resp);    
            
        } else if (method.equals(METHOD_DELETE)) {
            doDelete(req, resp);
            
        } else if (method.equals(METHOD_OPTIONS)) {
            doOptions(req,resp);
            
        } else if (method.equals(METHOD_TRACE)) {
            doTrace(req,resp);
            
        } else {
    
            String errMsg = lStrings.getString("http.method_not_implemented");
            Object[] errArgs = new Object[1];
            errArgs[0] = method;
            errMsg = MessageFormat.format(errMsg, errArgs);
            
            resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
        }
        }
    
        private void maybeSetLastModified(HttpServletResponse resp,
                          long lastModified) {
        if (resp.containsHeader(HEADER_LASTMOD))
            return;
        if (lastModified >= 0)
            resp.setDateHeader(HEADER_LASTMOD, lastModified);
        }
     
        public void service(ServletRequest req, ServletResponse res)
        throws ServletException, IOException
        {
        HttpServletRequest    request;
        HttpServletResponse    response;
        
        try {
            request = (HttpServletRequest) req;
            response = (HttpServletResponse) res;
        } catch (ClassCastException e) {
            throw new ServletException("non-HTTP request or response");
        }
        service(request, response);
        }
    }
    
    class NoBodyResponse implements HttpServletResponse {
        private HttpServletResponse        resp;
        private NoBodyOutputStream        noBody;
        private PrintWriter            writer;
        private boolean            didSetContentLength;
    
        // file private
        NoBodyResponse(HttpServletResponse r) {
        resp = r;
        noBody = new NoBodyOutputStream();
        }
    
        // file private
        void setContentLength() {
        if (!didSetContentLength)
          resp.setContentLength(noBody.getContentLength());
        }
    
        public void setContentLength(int len) {
        resp.setContentLength(len);
        didSetContentLength = true;
        }
    
        public void setCharacterEncoding(String charset)
          { resp.setCharacterEncoding(charset); }
    
        public void setContentType(String type)
          { resp.setContentType(type); }
    
        public String getContentType()
          { return resp.getContentType(); }
    
        public ServletOutputStream getOutputStream() throws IOException
          { return noBody; }
    
        public String getCharacterEncoding()
        { return resp.getCharacterEncoding(); }
    
        public PrintWriter getWriter() throws UnsupportedEncodingException
        {
        if (writer == null) {
            OutputStreamWriter    w;
    
            w = new OutputStreamWriter(noBody, getCharacterEncoding());
            writer = new PrintWriter(w);
        }
        return writer;
        }
    
        public void setBufferSize(int size) throws IllegalStateException
          { resp.setBufferSize(size); }
    
        public int getBufferSize()
          { return resp.getBufferSize(); }
    
        public void reset() throws IllegalStateException
          { resp.reset(); }
          
          public void resetBuffer() throws IllegalStateException
          { resp.resetBuffer(); }
    
        public boolean isCommitted()
          { return resp.isCommitted(); }
    
        public void flushBuffer() throws IOException
          { resp.flushBuffer(); }
    
        public void setLocale(Locale loc)
          { resp.setLocale(loc); }
    
        public Locale getLocale()
          { return resp.getLocale(); }
    
        public void addCookie(Cookie cookie)
          { resp.addCookie(cookie); }
    
        public boolean containsHeader(String name)
          { return resp.containsHeader(name); }
    
        /** @deprecated */
        public void setStatus(int sc, String sm)
          { resp.setStatus(sc, sm); }
    
        public void setStatus(int sc)
          { resp.setStatus(sc); }
    
        public void setHeader(String name, String value)
          { resp.setHeader(name, value); }
    
        public void setIntHeader(String name, int value)
          { resp.setIntHeader(name, value); }
    
        public void setDateHeader(String name, long date)
          { resp.setDateHeader(name, date); }
    
        public void sendError(int sc, String msg) throws IOException
          { resp.sendError(sc, msg); }
    
        public void sendError(int sc) throws IOException
          { resp.sendError(sc); }
    
        public void sendRedirect(String location) throws IOException
          { resp.sendRedirect(location); }
        
        public String encodeURL(String url) 
          { return resp.encodeURL(url); }
    
        public String encodeRedirectURL(String url)
          { return resp.encodeRedirectURL(url); }
          
        public void addHeader(String name, String value)
          { resp.addHeader(name, value); }
          
        public void addDateHeader(String name, long value)
          { resp.addDateHeader(name, value); }
          
        public void addIntHeader(String name, int value)
          { resp.addIntHeader(name, value); }
         
        public String encodeUrl(String url) 
          { return this.encodeURL(url); }
    
        public String encodeRedirectUrl(String url)
          { return this.encodeRedirectURL(url); }
    
    }
    
    class NoBodyOutputStream extends ServletOutputStream {
    
        private static final String LSTRING_FILE =
        "javax.servlet.http.LocalStrings";
        private static ResourceBundle lStrings =
        ResourceBundle.getBundle(LSTRING_FILE);
    
        private int        contentLength = 0;
    
        // file private
        NoBodyOutputStream() {}
    
        // file private
        int getContentLength() {
        return contentLength;
        }
    
        public void write(int b) {
        contentLength++;
        }
    
        public void write(byte buf[], int offset, int len)
        throws IOException
        {
        if (len >= 0) {
            contentLength += len;
        } else {
            // XXX
            // isn't this really an IllegalArgumentException?
            
            String msg = lStrings.getString("err.io.negativelength");
            throw new IOException("negative length");
        }
        }
    }

    ------------------------------------------------------------------------------------->

      最后再说说ServletContext的作用:

      它是一个接口javax.servlet.ServletContext,tomcat等web容器在启动时会创建一个实例,服务器关闭时销毁。主要作用是在一个web项目中共享数据、管理web项目资源,为整个web配置公共信息等。

      api:

    web项目中共享数据:提供属性操作  --xxxAttribute
            setAttribute(String name,Object obj ) 给web项目公共区域存放内容。(任意内容)
            getAttribute(String name) 通过指定名称获得内容
            removeAttribute(String name) 通过指定名称移除内容。
            如果不想使用数据,要么移除,要么关闭服务器。
    整个web项目初始化参数
            getInitParameter(java.lang.String name) 获得指定名称,初始化参数的值
            getInitParameterNames() 获得所有的初始化参数的名称
            web.xml 配置 整个web项目的初始化
            <context-param><param-name><param-value>
            spring 在web项目中配置<context-param><param-name>contextConfigLocation<param-value>classpath:applicationContext.xml
    获得web项目资源
            String getRealPath(java.lang.String path) 获得发布到tomcat下的指定资源路径
            例如:getRealPath("/WEB-INF/web.xml")
            获得实际路径:D:java omcatapache-tomcat-7.0.53webappsTestServletWEB-INFweb.xml
            InputStream getResourceAsStream(java.lang.String path)  与getRealPath使用相同,返回不同
            getResourcePaths(java.lang.String path)  指定路径下的所有内容。
            例如:getResourcePaths("/WEB-INF/")

  • 相关阅读:
    IWorkspaceFactory pWorkspaceFactory = new ShapefileWorkspaceFactoryClass(); 时,报COMException
    Asp.net MVC 发布到IIS6
    String.Net “System.TypeInitializationException”类型的未经处理的异常在 Spring.NetDemo.exe 中发生
    C#通过外部别名,解决DLL冲突问题
    c# DPI SCale
    c# 技巧
    正则笔记
    php & c# DES
    WPF页面切换
    C# 委托与事件
  • 原文地址:https://www.cnblogs.com/bruceChan0018/p/5868504.html
Copyright © 2011-2022 走看看