servletresponse获取返回内容 servlet返回文件_servlet注释路径无效


我们在开发中无时无刻都在与Servlet进行接触,只是因为框架的封装性,我们很少直接地去操作servlet,但再怎么封装,基本的思路都不会变化,变得只是实现的方式,

Servlet是什么:

网上的回答基本是Servlet是Java类,用于处理业务逻辑,

详细一点说Servlet确实是Java类,他是在Tomcat包中的,我们知道Tomcat是服务器,他为我们封装Request和Response,我们只需要实现Servlet接口就可以拿到封装好的Request和Response对象,是不是很方便呢,那么Servlet起到的作用就是在拿到封装好的Request后进行业务逻辑处理,然后返回Response,Servlet的整个生命周期由Tomcat控制,

因此,通过这个就能很好的实现开发业务逻辑与Http封装的解藕,开发也会更加高效,

Servlet的作用:

我们可以通过顶层接口来分析Servlet的作用:


servletresponse获取返回内容 servlet返回文件_初始化_02


这几个方法都是由容器去调用,我们自己去调用是无效的,

  1. init,这个接受一个容器帮我们封装好的ServletConfig,然后保存到本地
  2. getServletConfig返回先前保存到本地的ServletConfig
  3. getServletInfo返回一些version或者author等信息
  4. service接受请求对象,用作开发人员业务处理,完毕后返回响应对象
  5. destroy,容器销毁servlet

我们去来到源码中的GenericServlet,看看他是怎样为我们去实现的:


public abstract class GenericServlet implements Servlet, ServletConfig{
    private transient ServletConfig config;

    @Override
    public void init(ServletConfig config) throws ServletException {
        this.config = config;
        this.init();
    }

    @Override
    public String getInitParameter(String name) {
        return getServletConfig().getInitParameter(name);
    }

    @Override
    public abstract void service(ServletRequest req, ServletResponse res)
            throws ServletException, IOException;

    @Override
    public ServletConfig getServletConfig() {
        return config;
    }
}


这里截取了部分方法实现,可以看到,使用了模板方法模式,

反正我手长:模板方法模式zhuanlan.zhihu.com


servletresponse获取返回内容 servlet返回文件_Web_03


GenericServlet是abstract类,你可以很经常地在abstract类中看见这种设计,

另外还有一个HttpServlet,

它的注释让我们不要去实现service方法,因为他已经为我们封装了请求分发的逻辑,比如判断一个请求是get还是post,然后分发到具体的方法上去,


if (method.equals(METHOD_GET)) {
            doGet(req, resp);

        } else if (method.equals(METHOD_HEAD)) {
            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 {
            //
            // Note that this means NO servlet supports whatever
            // method was requested, anywhere on this server.
            //

            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);
        }


我们需要实现的是doGet、doPost这些方法,在里面写我们的业务逻辑,这里又有模板方法模式的身影


Servlet有两个息息相关的类,

ServletContext和ServletConfig,

对应JSP中九大作用域中的application和config对象,本质是用于做数据分享,

ServletContext:

Web应用有且仅有一个ServleContext,在应用起动的时候会被创建,他可以实现应用内的数据共享,

但是仅限单机版的应用程序,因为他仅仅是保存在一个JVM创建的上下文中,如果是分布式的,那建议使用数据库、session或者其他组件来代替

ServletConfig:


/**
 * A servlet configuration object used by a servlet container to pass
 * information to a servlet during initialization.
 */


用于容器向Servlet传递信息,

在ServletConfig和ServletContext都有getInitParameter方法, 这两个方法的都能从web.xml中获取参数,但是是有区别的。

可以在xml中配置,


<!-- 通过ServletContext#getInitParameter获取 -->    
<context-param>
       <param-name>test</param-name>
       <param-value>ServletContext</param-value>
    </context-param>
    
    <servlet>
      <servlet-name>testServletConfig</servlet-name>
      <servlet-class>com.web.test.TestServletConfig</servlet-class>
      <!-- 通过ServletConfig#getInitParameter获取 -->    
      <init-param>
         <param-name>testServletConfig</param-name>
         <param-value>getFromServletConfig</param-value>
      </init-param>
       <init-param>
         <param-name>encode</param-name>
         <param-value>utf-8</param-value>
      </init-param>
    </servlet>


如何获得ServletContext和ServletConfig:

ServletConfig:可以通过Servlet#getServletConfig获取,该方法就在Servlet中,Servlet是在ServletContext初始化之后才初始化(Servlet可以在Web应用启动或者发送请求的时候初始化,这要看load-on-startup的配置,当这个值>=0(相反为不配置或者<0)时,Web应用启动的时候就会初始化),Servlet初始化之后你才能获得ServletConfig。

ServletContext:在web.xml中读取到<context-param>的时候就会创建ServletContext,然后将<context-param>中的值(配置文件的地址)塞到ServletContext中,

所以理论上来说,这一步之后,Web容器中的内容都能获取ServletContext了,就看源码设计者觉得哪个地方需要就提供一个方法,然后Tomcat启动的时候会负责调用方法或者注入ServletContext等一系列操作:

  1. 实现WebApplicationInitializer接口
  2. 注册监听器,实现ServletContextListener
  3. ServletConfig#getServletContext
  4. ServletRequest#getServletContext
  5. HttpSession#getServletContext

侧面也表现了ServletContext和ServletConfig的作用范围,

还有一个有意思的点,你只要是在能获取到ServletContext的地方,你就可以通过ServletContext#setAttribute来设置值,这个操作对整个Web应用都可见,不需要返回ServletContext,因为我前面说过Web应用有且仅有一个ServleContext,出现的地方都是传递的引用:


servletresponse获取返回内容 servlet返回文件_封装_04


servletresponse获取返回内容 servlet返回文件_servlet注释路径无效_05



JavaWeb项目中有一个WEB-INF的文件夹,可以放置一些不能被客户端直接访问的数据,但不能被客户端访问并不代表不能被访问,实际上可以通过Servlet映射或则重定向来访问,


RequestDispatcher rd = request.getRequestDispatcher("./WEB-INF/view/a.jsp");
rd.forward(request, response);

<servlet>
  <servlet-name>Customer</servlet-name>
  <jsp-file>/WEB-INF/customer.jsp</jsp-file>
</servlet>
<servlet-mapping>
  <servlet-name>Customer</servlet-name>
  <url-pattern>/User</url-pattern>
</servlet-mapping>