Servelt

Servelt简介

什么是Servlet

Servlet是sun公司提供的一门用于开发动态web资源的技术,Java Web应用程序中所有的请求–响应都是由Servlet来完成的。
Servlet(Server Applet)是Java Servlet的简称,称为小服务程序或服务连接器,用Java编写的服务器端程序,具有独立于平台和协议的特性,主要功能在于交互式地浏览和生成数据,生成动态Web内容。
Servlet是Java Web的核心程序,所有的网址最终都交给Servlet来处理。 Servlet处理的基本流程图:
在这里插入图片描述
⑴ 客户端(可能是Web浏览器)通过HTTP提出请求;
⑵ Web服务器接收到该请求后,将其发送给Servlet进行处理;
⑶ Servlet会将处理的后结果向WEB服务器返回应答;
⑷ Web服务器将从Servlet获得的应答发送给客户端。

Servlet入门程序

将Java普通类变为Servlet的三种方式:1)实现javax.servlet.Servlet接口;2)继承javax.servlet.GenericServlet类;3)继承javax.servlet.http.HttpServlet类。而一般情况下,只需要继承HttpServlet类,重写doGet()和doPost()方法即可。从方法名中可以看出doGet()方法是处理GET请求,doPost()方法是处理POST请求。

public class HelloServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        PrintWriter out = response.getWriter();
        out.println("<html>");
        out.println("<head><title>Hello World</title></head>");
        out.println("<body>");
        out.println("<h1>第一个Java Web项目</h1>");
        out.println("</body>");
        out.println("</html>");
    }

@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    this.doGet(request,response);
}

}
注意:一个Servlet程序编译完成后,实际上是无法立即访问的,因为所有的Servlet程序都是以*.class的形式存在的,所以还需要在WEB-INF\web.xml文件中进行Servlet程序的映射配置。

<servlet>																					//   定义Servlet	 	
    <servlet-name>helloServlet</servlet-name>						//  进行Servlet映射	 		
    <servlet-class>com.luhui.HelloServlet</servlet-class>  	       // 映射的Servlet类路径 	
</servlet>
<servlet-mapping> 											      // servlet-mapping: 映射路径
    <servlet-name>helloServlet</servlet-name>
    <url-pattern>/hello</url-pattern>						//  url-pattern页面的映射路径
</servlet-mapping>
//servlet: servlet-name:

此时就可以访问了:http://127.0.0.1:8080/JavaWeb/hello ;JavaWeb是配置的项目名。
HttpServlet指能够处理HTTP请求的servlet,它在原有Servlet接口上添加了一些与HTTP协议处理方法,它比Servlet接口的功能更为强大。因此开发人员在编写Servlet时,通常应继承这个类,而避免直接去实现Servlet接口。HttpServlet在实现Servlet接口时,覆写了service方法,该方法体内的代码会自动判断用户的请求方式,如为GET请求,则调用HttpServlet的doGet方法,如为Post请求,则调用doPost方法。因此,开发人员在编写Servlet时,通常只需要覆写doGet或doPost方法,而不要去覆写service方法。

Servlet与普通Java类的区别

Servlet是一个供其他Java程序(Servlet引擎)调用的Java类,它不能独立运行,它的运行完全由Servlet引擎来控制和调度。
针对客户端的多次Servlet请求,通常情况下,服务器只会创建一个Servlet实例对象,也就是说Servlet实例对象一旦创建,它就会驻留在内存中,为后续的其它请求服务,直至web容器退出,servlet实例对象才会销毁。

Servlet的URL路径

Servlet访问URL映射配置

由于客户端是通过URL地址来访问web服务器中的资源,因此Servlet程序要想被外界访问,就需要把Servlet程序映射到一个URL地址上,这个工作在web.xml文件中使用元素和元素完成。
元素用于注册Servlet,它包含有两个主要的子元素:和,分别用于设置Servlet的注册名称和Servlet的完整类名。
一个元素用于映射一个已注册的Servlet的一个对外访问路径,它包含有两个子元素:和,分别用于指定Servlet的注册名称和Servlet的对外访问路径。例如:

<servlet>
    <servlet-name>helloServlet</servlet-name>				
    <servlet-class>com.luhui.HelloServlet</servlet-class>  
</servlet>
<servlet-mapping>
    <servlet-name>helloServlet</servlet-name>
    <url-pattern>/hello</url-pattern>
</servlet-mapping>

需要注意的是对于每一个Servlet实际上都可以配置多个名称,即多个元素的子元素的设置值可以是同一个Servlet的注册名,但是元素的子元素的值就不可以相同,否则启动就会报错。

<servlet-mapping>
    <servlet-name>helloServlet</servlet-name>
    <url-pattern>/hello.jsp</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>helloServlet</servlet-name>
    <url-pattern>/hello.aspx</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>helloServlet</servlet-name>
    <url-pattern>/hello.php</url-pattern>
</servlet-mapping>

通过上面的配置,当我们想访问名称是HelloServlet的Servlet时,可以使用如下的几个地址去访问:HelloServlet被映射到了多个URL上:

http://localhost:8080/JavaWebt/hello
http://localhost:8080/JavaWeb/hello.jsp
http://localhost:8080/JavaWeb/hello.php
http://localhost:8080/JavaWeb/hello.aspx

1.2.2、Servlet访问URL使用通配符映射 
在Servlet映射到的URL中也可以使用
通配符,但是只能有两种固定的格式:
一种格式是"*.扩展名",
另一种格式是以正斜杠(/)开头并以"/*"结尾:" /* "。

<servlet-mapping>
    <servlet-name>anyName</servlet-name>
    <url-pattern>/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>anyName</servlet-name>
    <url-pattern>*.do</url-pattern>
</servlet-mapping>

例如:

<servlet-mapping>
    <servlet-name>helloServlet</servlet-name>
    <url-pattern>/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>helloServlet</servlet-name>
    <url-pattern>*.do</url-pattern>
</servlet-mapping>

星号:* 可以匹配任意的字符,所以此时可以用任意的URL去访问HelloServlet这个Servlet。对于如下的一些映射关系:

		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

如果某个Servlet的映射路径仅仅为一个正斜杠(/),那么这个Servlet就成为当前Web应用程序的缺省Servlet。凡是在web.xml文件中找不到匹配的元素的URL,它们的访问请求都将交给缺省Servlet处理,也就是说,缺省Servlet用于处理所有其他Servlet都不处理的访问请求。

<servlet>
    <servlet-name>ServletDemo</servlet-name>
    <servlet-class>com.luhui.ServletDemo</servlet-class>
</servlet>
<!-- 将ServletDemo配置成缺省Servlet -->
<servlet-mapping>
    <servlet-name>ServletDemo</servlet-name>
    <url-pattern>/</url-pattern>
</servlet-mapping>

当访问不存在的Servlet时,就使用配置的默认Servlet进行处理。

Servlet生命周期

Servlet生命周期

每个Servlet都有自己的生命周期,Servlet的生命周期由web服务器来维护。生命周期包括加载程序、初始化、服务、销毁、卸载5个部分:
在这里插入图片描述

  • init方法
    在一个Servlet的生命周期中,init方法只会被执行一次,之后无论用户执行多少次请求,都不会在调用该方法。关于init方法的执行时机,有两种方式可选,一般的是在服务器启动后第一个用户请求改Servlet是调用,你也可以设置该Servlet在服务器启动后自动执行。init方法负责简单的创建或者加载一些数据,这些数据将用于该Servlet的整个生命周期中。
  • service方法
    当一个客户请求改Servlet时,实际的处理工作全部有service方法来完成,service方法用来处理客户端的请求,并生成格式化数据返回给客户端。每一次请求服务器都会开启一个新的线程并执行一次service方法,service根据客户端的请求类型,调用doGet、doPost等方法。service是由web容器来调用的,我们无需对service具体内容做任何处理,service会自动的根据客户端的请求类型去调用doGet、doPost等方法,所以我们只需要做好doGet、doPost方法的实现就可以了。
  • destroy方法
    该方法在整个生命周期中,也是只会被调用一次,在Servlet对象被销毁是调用,在servlet中,我们可以做一些资源的释放等操作,执行destory方法之后的servlet对象,会等待jvm虚拟机的垃圾回收机制择时回收。
  • doGet、doPost方法
    实际的业务处理流程,service根据客户端的请求类型来自动匹配需要执行那个方法。

public class LifeServlet extends HttpServlet{
@Override
public void destroy() {
System.out.println(“销毁”);
}
@Override
public void init() throws ServletException {
System.out.println(“初始化”);
} }

取得初始化配置信息

可以通过ServletConfig的config对象来获取web.xml中配置的初始化参数。在GenericServlet类中有重载方法init(ServletConfig config)可以找到ServletConfig 接口。
在Servlet的配置文件web.xml中,可以使用一个或多个标签为servlet配置一些初始化参数。

<servlet>
    <servlet-name>servletConfigServlet</servlet-name>
    <servlet-class>com.luhui.ServletConfigServlet</servlet-class>
    <!--配置ServletConfigServlet的初始化参数 -->
    <init-param>
        <param-name>username</param-name>
        <param-value>luhui</param-value>
    </init-param>
    <init-param>
        <param-name>password</param-name>
        <param-value>123456</param-value>
    </init-param>
    <init-param>
        <param-name>charset</param-name>
        <param-value>UTF-8</param-value>
    </init-param>
</servlet>
<servlet-mapping>
    <servlet-name>servletConfigServlet</servlet-name>
    <url-pattern>/servletConfigServlet</url-pattern>
</servlet-mapping>

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

public class ServletConfigServlet extends HttpServlet{

    private String username;
    private String password;
    private String charset;
    
    @Override
    public void init(ServletConfig config) throws ServletException {
        username = config.getInitParameter("username");
        password = config.getInitParameter("password");
        charset = config.getInitParameter("charset");
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("初始化参数:"+username+"\t"+password+"\t"+charset);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doGet(req, resp);
    }
}

Servlet之间的跳转

Servlet之间可以相互跳转,从一个Servlet程序跳转到另一个Servlet。利用Servlet的跳转可以把一个项任务按模块分开。

客户端跳转(转向Forward)

转向(Forward)是通过RequestDispatcher对象的forward(HttpServletRequest request,HttpServletResponse response)方法来实现的。而RequestDispatcher对象可以通过HttpServletRequest的getRequestDispatcher(String path)方法获得。

public class ForwardServlet extends HttpServlet{

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String path = request.getParameter("path");
        System.out.println(path);
        if("file".equals(path)){
            request.getRequestDispatcher("/WEB-INF/web.xml").forward(request,response);
        }else if("jsp".equals(path)){
            request.getRequestDispatcher("/forword.jsp").forward(request,response);
        }else if("servlet".equals(path)){
            request.getRequestDispatcher("/lifeServlet").forward(request,response);
        }else {
            System.out.println("缺少参数");
        }
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doGet(request, response);
    }
}

客户端跳转(重定向Redirect)

在Servlet中可以使用HttPServletResponse接口的sendRedirect()方法来进行重定向。

public class RedirectServlet extends HttpServlet{
    private Map<String, Integer> map = new HashMap<String, Integer>();

    @Override
    public void init() throws ServletException {
        map.put("/setup.exe",0);
        map.put("/application.zip",0);
        map.put("/01.mp3",0);
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String fileName = req.getParameter("filename");
        if(fileName != null){
            int hit = map.get(fileName);
            map.put(fileName,hit++);
            resp.sendRedirect(req.getContextPath()+fileName);
        }else{
            resp.setCharacterEncoding("utf-8");
            resp.setContentType("text/html");
            PrintWriter out = resp.getWriter();
            out.println("<html>");
            out.println("<head><title>文件下载</title></head>");
            out.println("<body>");
            out.println("<fieldset align=center style=width:90%><legend>文件下载</legend");
            out.println("<table width=100%>");
            out.println("<tr>");
            out.println("<td><b>文件名</b></td>");
            out.println("<td><b>下载次数</b></td>");
            out.println("<td></td>");
            out.println("</tr><br>");
            for(Map.Entry<String,Integer> entry : map.entrySet()){
                out.println("<tr>");
                out.println("<td>"+entry.getKey()+"</td>");
                out.println("<td>"+entry.getValue()+"</td>");
                out.println("<td><a href = '"+req.getRequestURI() +"?filename="+entry.getKey()+"'target='blank'     onclick = 'location=location;'>下载</a> </td>");
                out.println("</tr><br>");
            }
            out.println("</table>");
            out.println("</body>");
            out.println("</html>");
        }
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}

猜你喜欢

转载自blog.csdn.net/weixin_38960050/article/details/88917882