Java - Servlet完全教程

简书 賈小強
转载请注明原创出处,谢谢!

Servlet是一种允许响应请求的Java类。虽然Servlet可以响应任何类型的请求,但它们通常被用来响应网络请求。一个Servlet必须部署在Java servlet容器中,它才能成为可用的。虽然许多开发者利用Servlet框架如Java Server Pages (JSP)Java Server Faces (JSF),但实际上这两种技术通过servlet容器在幕后将页面编译为Java servlet。也就是说,Java servlet技术的基本知识对任何Java web开发都很有用。

在本教程中,我们将涵盖以下主题,从而获得Java servlet技术的整体认识。

目录

  • 编写第一个Servlet
  • Servlet的生命周期方法
  • 使用@WebServlet注解开发Servlet
  • 打包并部署Servlet到Tomcat服务器
  • Servlet响应中写入动态内容
  • Servlet接受参数处理并响应
  • 监听Servlet容器事件
  • Servlet传入初始化参数
  • 给指定的请求增加Servlet过滤器
  • Servlet下载二进制文件
  • 用RequestDispatcher.forward()将请求内部转发到另一个Servlet
  • 用HttpServletResponse.sendRedirect()将请求重定向到另一个Servlet
  • Servlet读写cookie
  • 让我们开始一步一步学习Servlet

编写第一个Servlet

下面是一个非常简单的Servlet,实际上你需要写的代码代码非常少

package com.bill.servlets;
 
import java.io.IOException;
import java.io.PrintWriter;
 
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
public class MyFirstServlet extends HttpServlet {
 
    private static final long serialVersionUID = -1915463532411657451L;
 
    @Override
    protected void doGet(HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException 
    {
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();
        try {
            // Write some content
            out.println("<html>");
            out.println("<head>");
            out.println("<title>MyFirstServlet</title>");
            out.println("</head>");
            out.println("<body>");
            out.println("<h2>Servlet MyFirstServlet at " + request.getContextPath() + "</h2>");
            out.println("</body>");
            out.println("</html>");
        } finally {
            out.close();
        }
    }
     
    @Override
    protected void doPost(HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException {
        //Do some other work
    }
 
    @Override
    public String getServletInfo() {
        return "MyFirstServlet";
    }
}

用一个web.xml文件将上面的MyFirstServlet注册在web容器中。

<?xml version="1.0"?>
<web-app     xmlns="http://xmlns.jcp.org/xml/ns/Javaee"
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee 
            http://xmlns.jcp.org/xml/ns/javaee/web-app_3_0.xsd"
            version="3.0">
             
    <welcome-file-list>
        <welcome-file>/MyFirstServlet</welcome-file>
    </welcome-file-list>
     
    <servlet>
        <servlet-name>MyFirstServlet</servlet-name>
        <servlet-class>com.bill.servlets.MyFirstServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>MyFirstServlet</servlet-name>
        <url-pattern>/MyFirstServlet</url-pattern>
    </servlet-mapping>
     
</web-app>

你可能想知道上面MyFirstServlet的完成了哪些重要的事情。

  1. MyFirstServlet继承自HttpServlet。这是强制性的,因为所有的Servlet必须继承javax.servlet.GenericServletjavax.servlet.http. HttpServlet
  2. 重写了doGet()和doPos()方法。这些方法定义在HttpServlet类中。每当GET或POST请求到来时,它被映射到其各自对应的方法(例如,如果您发送一个 HTTP GET请求,然后servlet的doGet()方法被调用。
  3. 还有一些你可以重写的其他方法,被用来控制应用程序,比如getServletInfo()。
  4. HttpServletRequestHttpServletResponse是doxxx()方的默认参数类型。我们将在以后的章节中更多地了解这两种类型对应的对象。

这就是了解一个简单Servlet需要知道的的全部内容。

Servlet的生命周期方法

在应用程序中,每当加载并使用Servlet时会发生一系列事件,如初始化和销毁。这些被称为Servlet的生命周期事件(或方法)。让我们多了解一些关于它们的故事。

init(),service(),和destroy()是三个在Servlet的生命周期中至关重要的方法。它们由每个Servlet实现,并在特定时间被调用。

1)在Servlet生命周期的初始阶段,web容器通过调用init()方法初始化Servlet实例,同时传入一个实现javax.servlet.ServletConfig接口的对象。这个配置对象允许Servlet访问在web.xml文件中定义的键值对值初始化参数。这只在Servlet实例的生命周期中调用一次。
init方法定义如下所示:

public void  init() throws ServletException {
    //custom initialization code
}

2)在初始化之后,Servlet实例可以为客户请求提供服务。web容器调用Servlet的service()方法处理每个请求。service方法判断请求的种类或者将请求转发到哪个方法里处理更加合适。Servlet的开发人员必须为这些方法提供一个实现。如果Servlet未实现这个方法,那么请求将调用父类的方法处理,通常会给请求者导致返回一个错误。

几乎没有必要重写此方法。

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

3)最后,web容器调用destroy()方法终止Servlet的服务。如果希望在Servlet不可用之前关闭或销毁某些文件系统或网络资源,则应该调用此方法。destory()方法和init()方法一样在Servlet整个生命周期中只被调用一次。

public void destroy() {
    //
}

通常情况下,你不需要重写Servlet的这些方法。

使用@WebServlet注解开发servlet

如果你不是很喜欢xml配置,而特别喜欢注释, Servlets API也有这样的功能。您可以使用@WebServlet ,如下的例子,那么你不需要在web.xml中做任何事情。在运行时会自动将Servlet注册到容器,并像往常一样处理它。

package com.bill.servlets;
 
import java.io.IOException;
import java.io.PrintWriter;
 
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
@WebServlet(name = "MyFirstServlet", urlPatterns = {"/MyFirstServlet"})
public class MyFirstServlet extends HttpServlet {
 
    private static final long serialVersionUID = -1915463532411657451L;
 
    @Override
    protected void doGet(HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException 
    {
        //Do some work
    }
     
    @Override
    protected void doPost(HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException {
        //Do some other work
    }
}

打包并部署servlet到Tomcat服务器

如果您使用的是任何IDE(如Eclipse),那么打包和部署应用程序非常简单。右键单击项目> Run As > Run As Server。如果尚未完成,就配置服务器,然后就完成了。
如果您不使用任何IDE,那么您需要做一些额外的工作,例如从命令提示符编译应用程序,使用Ant创建WAR文件等,但我确信现在每个人都使用一些IDE进行开发,所以我不会在这里浪费更多的时间。
当您在Tomcat中部署完我们写的第一个Servlet,然后在浏览器地址栏输入http://localhost:8080/servletexamples/MyFirstServlet,回车,你将得到下面的响应。

在Servlet响应中写入动态内容

Servlet之所以非常用用的原因是它允许给网页内容动态的加入一些内容。内容可以从服务器本身、数据库、另一个web站点或许多其他可访问的web资源。Servlet不是静态的网页,他们是动态的,这是它们最关键的地方。

让我们以Servlet为例,它负责向用户显示当前日期和时间,以及他的名字和一些自定义消息,代码如下。

package com.bill.servlets;
 
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
 
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
@WebServlet(name = "CalendarServlet", urlPatterns = {"/CalendarServlet"})
public class CalendarServlet extends HttpServlet {
 
    private static final long serialVersionUID = -1915463532411657451L;
 
    @Override
    protected void doGet(HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException 
    {
         
        Map<String,String> data = getData();
         
        response.setContentType("text/html;charset=UTF-8");
        PrintWriter out = response.getWriter();
        try {
            // Write some content
            out.println("<html>");
            out.println("<head>");
            out.println("<title>CalendarServlet</title>");
            out.println("</head>");
            out.println("<body>");
            out.println("<h2>Hello " + data.get("username") + ", " + data.get("message") + "</h2>");
            out.println("<h2>The time right now is : " + new Date() + "</h2>");
            out.println("</body>");
            out.println("</html>");
        } finally {
            out.close();
        }
    }
     
    //This method will access some external system as database to get user name, and his personalized message
    private Map<String, String> getData() 
    {
        Map<String, String> data = new HashMap<String, String>();
        data.put("username", "Guest");
        data.put("message",  "Welcome to my world !!");
        return data;
    }
}

当你在Tomcat中运行上面的Servlet,然后在浏览器中请求http://localhost:8080/servletexamples/CalendarServlet,你将得到下面的响应

Servlet接受参数处理并响应

Servlet可以很容易地创建web应用程序,给用户的请求返回响应。它们能够提供HTTP响应,并在同一代码体中处理业务逻辑。用于处理业务逻辑的能力使Servlet比标准的HTML代码更强大。

在实际应用程序中,HTML Web表单包含发送给Servlet的参数。然后servlet以某种方式处理这些参数,并给客户端返回一个响应。在一个HttpServlet对象的情况下,客户端是一个web浏览器,响应是一个网页。表单的action属性标签指定了谁来处理表单中所包含的参数。

调用HttpServletRequest对象的getparameter()方法获取请求参数,通过id获得你想得到的参数。

String value1 = req.getParameter("param1");
String value1 = req.getParameter("param2");

一旦获得这些值,就可以根据需要进行处理。然后为客户机返回响应,正如我们在以上章节中讨论的那样,用HttpServletResponse类型的对象给客户端返回响应。

一个基本的请求-处理-响应的流程如下:

@Override
protected void doGet(HttpServletRequest request,
        HttpServletResponse response) throws ServletException, IOException 
{
     
    response.setContentType("text/html;charset=UTF-8");
    PrintWriter out = response.getWriter();
     
    String username = request.getParameter("username");
    String password = request.getParameter("password");
     
    boolean success = validateUser(username, password);
     
    try {
        // Write some content
        out.println("<html>");
        out.println("<head>");
        out.println("<title>LoginServlet</title>");
        out.println("</head>");
        out.println("<body>");
 
        if(success) {
            out.println("<h2>Welcome Friend</h2>");
        }else{
            out.println("<h2>Validate your self again.</h2>");
        }
         
        out.println("</body>");
        out.println("</html>");
    } finally {
        out.close();
    }
}

你需要从HttpServletResponse对象获得PrintWriter对象,给客户端返回内容。任何写入它的内容将被写入OutputStream,然后数据将被发送回客户端。

监听Servlet容器事件

有时候知道在容器中发生的某些事件是非常有用的。这个概念在许多不同的情况下都是有用的,但大多数情况下,它可能被用于在启动时初始化,关闭时清理。一个Servlet可以在容器注册Listener,以监听它何时启动或关闭。因此,通过侦听此类事件,Servlet有机会在发生某些事件时执行某些操作。

要创建一个基于容器的事件的监听器,你必须实现一个ServletContextListener接口的类。需要实现contextInitialized()和contextDestroyed()方法。这两种方法都接受一个ServletContextEvent作为参数,并分别在每次Servlet容器初始化或关闭时被自动调用。

用给容器注册监听器,可以使用以下技术之一:

  1. 利用@WebListener 注解。
  2. 在web.xml中注册监听器。
  3. 使用ServletContext的addListener()方法。

请注意,ServletContextListener不是Servlet API中的唯一监听器。还有更多,比如

  • javax.servlet.servletrequestlistener
  • javax.servlet.servletrequestattrbitelistener
  • javax.servlet.servletcontextlistener
  • javax.servlet.servletcontextattributelistener
  • javax.servlet.httpsessionlistener
  • javax.servlet.httpsessionattributelistener

根据你希望监听到的事件实现你自己的监听器类,如HttpSessionListener将监听每当户创建一个新的用户Session或者销毁时的事件。

给Servlet传入初始化参数

今天大多数应用程序需要设置一些在应用程序/控制器启动时传给它们配置参数。Servlet也可以在它们被第一请求的时候接受初始化参数。

显然,你可以在Servlet本身硬编码的配置,但改变任何他们需要重新编译一次整个应用程序,没有人会喜欢这样做。

<web-app>
    <servlet>
        <servlet-name>SimpleServlet</servlet-name>
        <servlet-class>com.bill.servlets.SimpleServlet</servlet-class>
         
        <!-- Servlet init param -->
        <init-param>
            <param-name>name</param-name>
            <param-value>value</param-value>
        </init-param>
 
    </servlet>
 
</web-app>

一旦设置,该参数通过调用 getServletConfig().getInitializationParameter() 和传递的参数的名称来得到并使用,如下面的代码行所示:

String value = getServletConfig().getInitParameter("name");

给指定的请求增加Servlet过滤器

Web过滤器对于在访问给定URL求之前调用某些功能,它非常有用。相比通过一个固定的URL请求一个Servlet,过滤器匹配一个模式的URL,在这些URL对应的Servlet调用之前被调用。这在许多情况下非常有用,如日志记录、身份验证或其他服务。

过滤器必须实现javax.servlet.Filter接口。方法包含init (),destroy(),和dofilter()方法。init ()和destroy()方法由容器调用。dofilter()方法被用来定义过滤器类所要完成的任务。如果你想要过滤器链,或者对应一个URL有多个过滤器,在web.xml配置文件中按顺序配置即可。

在web.xml配置文件中配置一个过滤器,使用XML的<filter> 和<filter-mapping>元素以及与它们相关的子元素标签。

<filter>
    <filter-name>LoggingFilter</filter-name>
    <filter-class>LoggingFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>LogingFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

如果你想使用注释来配置特定的Servlet过滤器,你可以使用@WebFilter注释。

用Servlet下载二进制文件

下载文件是几乎所有web应用程序的基本任务。要下载文件,Servlet必须提供与下载文件匹配的相同类型的响应,它还必须在响应标头中指出要包含附件,如下所示。

String mimeType = context.getMimeType( fileToDownload );
response.setContentType( mimeType != null ? mimeType : "text/plain" );
response.setHeader( "Content-Disposition", "attachment; filename=\"" + fileToDownload + "\"" );

你可以通过给ServletContext的getResourceAsStream() 方法传一个路径,获得一个你需要下载(被存在服务器的文件系统中)的文件的引用。这将返回一个InputStream对象可以用来读取文件内容。然后创建一个字节缓冲区,用于读取文件时从文件中获取数据块。最后真正的任务是读取文件内容并将它们复制到输出流中。这是通过使用一个while循环,这将不断读取InputStream直到文件结束。使用循环将数据块读入并写入输出流。在这之后,ServletOutputStream 对象flush方法被调用,来清除内容和释放资源。

让我们看示例代码

private void downloadFile(HttpServletRequest request, HttpServletResponse response, String fileToDownload) throws IOException
    {
        final int BYTES = 1024;
        int length = 0;
         
        ServletOutputStream outStream = response.getOutputStream();
        ServletContext context = getServletConfig().getServletContext();
 
        String mimeType = context.getMimeType( fileToDownload );
        response.setContentType( mimeType != null ? mimeType : "text/plain" );
        response.setHeader( "Content-Disposition", "attachment; filename=\"" + fileToDownload + "\"" );
 
        InputStream in = context.getResourceAsStream("/" + fileToDownload);
         
        byte[] bbuf = new byte[BYTES];
 
        while ((in != null) && ((length = in.read(bbuf)) != -1)) {
            outStream.write(bbuf, 0, length);
        }
 
        outStream.flush();
        outStream.close();
    }

用RequestDispatcher.forward()将请求内部转发到另一个servlet

有时,你的应用程序需要一个Servlet完成部分任务,然后让其他servlet完成剩下的任务。此外,请求应该在不将客户机重定向到另一个URL的情况下进行传递,即浏览器中的URL不应更改。

调用ServletContext对象getRequestDispatcher ()方法获得RequestDispatcher对象,这个对象可以被用来内部转发。getRequestDispatcher ()调用方法时,传递一个字符串包含要把请求的Servlet的名字。通过将HttpServletRequestHttpServletResponse传给RequestDispatcher的对象,然后调用forword()方法。然后内部转发到另一个Servlet

RequestDispatcher rd = servletContext.getRequestDispatcher("/NextServlet");
rd.forward(request, response);

用HttpServletResponse.sendRedirect()将请求转发到另一个servlet

尽管有时正如我们在上一节中看到的您不愿意通知用户,Servlet重定向已经发生,但在某些场景中,我们实际上希望用户知道。当访问应用程序中的特定URL时,您希望重定向浏览器到另一个URL。

要做到这一点,你需要调用HttpServletResponse 对象的sendRedirect()方法。
这个简单的重定向不会把HttpReuest的对象在servlet链条中传递。

用Servlet读写Cookie

许多应用程序希望将用户浏览历史的当前状态存储在客户机中,以便当用户再次返回应用程序时,他从离开的位置开始。通常,对于这个要求,使用cookie。您可以将cookie视为存储在客户机上的键值对数据。当从浏览器中发出请求时,浏览器可以读取或写入这些值。

简单地实例化一个新的Javax.servlet.http.Cookie类创建一个cookie对象。一旦实例化了cookie,就可以设置属性,这将有助于配置cookie。在下面例子中,cookie的setMaxAge()和setHttpOnly()方法被调用,设置cookie的有效期并防止客户端脚本访问。

由于Servlet 3.0 API,将cookie标记为HTTP。这使得cookie可以防止客户端脚本攻击,使cookie更加安全。

Cookie cookie = new Cookie("sessionId","123456789");
cookie.setHttpOnly(true);
cookie.setMaxAge(-30);
response.addCookie(cookie);

这里的response对象是传给doXXX()方法中的参数。

要从服务端获得cookie信息,请使用以下代码:

Cookie[] cookies = request.getCookies();
for(Cookie cookie : cookies)
{
    //cookie.getName();
    //cookie.getValue()
}

这就是本教程关于Servlet的所有技术。欢迎评论/反馈。

Happy Learning !!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容

  • 从三月份找实习到现在,面了一些公司,挂了不少,但最终还是拿到小米、百度、阿里、京东、新浪、CVTE、乐视家的研发岗...
    时芥蓝阅读 42,169评论 11 349
  • 这部分主要是与Java Web和Web Service相关的面试题。 96、阐述Servlet和CGI的区别? 答...
    杂货铺老板阅读 1,397评论 0 10
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,585评论 18 139
  • 0 系列目录# WEB请求处理 WEB请求处理一:浏览器请求发起处理 WEB请求处理二:Nginx请求反向代理 本...
    七寸知架构阅读 13,871评论 22 190
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,560评论 18 399