博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Servlet - 基础
阅读量:5282 次
发布时间:2019-06-14

本文共 22231 字,大约阅读时间需要 74 分钟。

Servlet

标签 : Java与Web


HTTP协议

HTTP(hypertext transport protocol),即超文本传输协议.这个协议详细规定了浏览器(Browser)和万维网服务器(WebServer)之间互相通信的规则.其主要特点可简单概括如下:

1) 简单快速: 客户端向服务器请求服务时,只需传送请求方法和路径, 因此使得HTTP服务器的程序规模小,通信速度快;
2) 灵活: HTTP允许传输任意类型的数据对象(传输类型由Content-Type控制);
3) 无连接: 无连接的含义是限制每次连接只处理一个请求;
4) 无状态: 无状态是指协议对于事务处理没有记忆能力(如果后续处理需要前面的信息,则必须重传.这样可能导致每次连接传送的数据量增大.但如果在服务器不需要先前信息时它的应答就会非常快快).


HTTP请求

一个HTTP请求通常包含三部分(中间已空行隔开):

请求行:        (方法 /统一资源标识符URI/协议/版本)请求头:        (Accept/Accept-Language等)空行:     (CRLF)请求体:        (携带的数据信息, GET请求没有)

HTTP请求可以使用HTTP标准中定义的所有请求类型, HTTP1.1支持7种请求类型, 但在互联网应用中最为常用的只有GETPOST.


HTTP-GET

GET /WeChat/cc3200/get_status.do HTTP/1.1Host: aliyunUser-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:45.0) Gecko/20100101 Firefox/45.0Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3Accept-Encoding: gzip, deflateConnection: keep-alive
  • 请求头解析
请求头 描述
User-Agent 浏览器与操作系统信息
Accept 当前浏览器可以接收的文档类型
Accept-Language 当前浏览器支持的语言
Accept-Encoding 当前浏览器支持的压缩格式:服务器会把数据压缩后再发送到网络中传输
Accept-Charset 当前浏览器支持的编码
Connection 当前浏览器支持的连接方式(keep-alive即保持一段时间的连接,默认为3000ms)
Cookie 如果不是第一次访问该网址,可能会在请求中把上次服务器响应的Cookie数据一并发送过去

HTTP-POST

POST /WeChat/cc3200/get_status.do HTTP/1.1Content-Length: 36Cache-Control: max-age=0Origin: http://localhost:8080Content-Type: application/x-www-form-urlencodedReferer: http://localhost:8080/test/...user_name=feiqing&user_password=pass
  • 请求头解析
请求头 描述
Referer 表明请求来自哪个页面
Content-Type application/x-www-form-urlencoded:表单数据类型,说明会使用URL编码来格式化数据
Content-Length 请求体长度
user_name=feiqing&user_password=pass 请求体: 请求携带的数据

HTTP响应

一个HTTP响应通常也包含三部分(中间已空行隔开):

响应行:        (协议/状态码/描述)响应头:        (Server/Content-Length/Set-Cookie等)空行:     (CRLF)响应体:        (携带的数据)

HTTP响应是由服务器发送给浏览器的数据,浏览器会根据HTTP响应来解析并显示内容:

HTTP/1.1 200 OKServer: Apache-Coyote/1.1Content-Length: 8Date: Sun, 17 Apr 2016 12:39:11 GMT    ...
  • 响应头解析
响应头 描述
Server 服务器信息
Content-Length 响应实体长度
Set-Cookie 响应给客户端的Cookie
Expires: -1; / Cache-Control: no-cache; / Pragma: no-cache; 设置浏览器不要缓存数据
Refresh 自动刷新页面

在HTML文件中可用<meta/>标签来设置响应头信息:


响应状态码

状态码说明了响应的真正含义:

状态 描述
200 请求成功
404 请求资源没找到
500 服务器内部错误
302 重定向: 表示服务器要求浏览器重新再发一个请求到服务器指定的一个Location
304 缓存未过期(服务器资源未曾修改), 详细可参考

Tomcat

Tomcat是一个免费开源的Serlvet容器,它是Apache基金会的Jakarta项目中的一个核心项目,由Apache,Sun和其它一些公司及个人共同开发而成. 由于有了Sun的参与和支持, 因此最新的Servlet和Jsp规范总能在Tomcat中得到体现.主页:.


Tomcat目录结构

  • bin: 存放可执行脚本文件(如startup.bat/startup.sh等)
  • conf: 存放Tomcat相关配置文件:
    • server.xml: 整个Tomcat运行环境配置(如端口号/虚拟主机等)
    • web.xml: 部署描述符文件(定义了默认JSP/Servlet处理规则,是所有web项目中WEB-INF/web.xml的父文件)
    • context.xml: 对所有应用的统一配置.
  • lib:Tomcat类库, 该目录中的jar包所有项目共享.
  • logs : Tomcat日志目录.
  • webapps:存放WEB应用,其每个子目录都是一个项目;
  • work:运行时生成的文件.

server.xml

  • 元素解析
元素 描述
<Server/> 根元素,整个Tomcat的配置信息
<Service/> 服务(在<Server/>中只能有一个<Service/>)
<Connector/> 连接
<Engine/> 引擎,是<Service/>组件核心
<Host/> 每个<Host/>元素表示一台虚拟主机.每台虚拟主机都有自己的主机名和项目目录
<Context/> 每个<Context/>元素表示一个应用.如果应用在<Host/>的appBase指定的目录下,那么可以不配置<Context/>元素,如果是外部应用,那么就必须配置<Context/>

Tomcat配置

1. 配置端口号

编辑%CATALANA_HOME%\conf\server.xml文件中的<Connector/>元素

2. 配置外部应用

配置外部应用之后, 项目就可以不用拷贝到webapps目录下,自定义项目存放位置,其配置方式有两种:

  • 1: 修改server.xml
    <Host/>元素中添加<Context/>元素

如果指定path为空(path=”“), 则默认访问的项目就是/home/www/test, 而不再是webapps下的ROOT.

  • 2: 编辑conf/catalana/localhost目录:
    新增test.xml文件

存放到%CATALANA_HOME%/conf/catalana/localhost目录下, 文件名即为应用名.


Servlet

Servlet技术核心就是Servlet接口,所有Servlet实现类都必须实现Servlet接口,Servlet容器(如Tomcat)会把Servlet类加载到内存并生成唯一实例,当有请求到来时调用其方法.

  • 实现Servlet方式有三种:
    1. 实现javax.servlet.Servlet接口
    2. 继承javax.servlet.GenericServlet
    3. 继承javax.servlet.http.HttpServlet

Servlet

Servlet接口定义如下

public interface Servlet {
public void init(ServletConfig config) throws ServletException; public ServletConfig getServletConfig(); public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException; public String getServletInfo(); public void destroy();}
方法 描述
init 在第一次请求该Servlet(默认)或容器启动时, Servlet容器就会调用init(), 且只调用一次
service 每次请求Servlet都会调用该方法
destroy 销毁Servlet时(卸载应用/关闭容器时), 调用该方法
  • HelloServlet
/** * @author jifang. * @since 2016/4/17 8:32. */public class HelloServlet implements Servlet {
private ServletConfig config; public void init(ServletConfig config) throws ServletException { System.out.println("init()..."); this.config = config; System.out.println("config: <" + config + ">"); } public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException { System.out.println("service()..."); System.out.println("req: <" + req + ">, res: <" + res + ">"); res.getWriter().print("

HelloServlet

"); } public void destroy() { System.out.println("destroy()..."); } public ServletConfig getServletConfig() { return this.config; } public String getServletInfo() { return null; }}
  • web.xml
JavaWeb
HelloServlet
com.fq.web.servlet.HelloServlet
HelloServlet
/hello_servlet.do
  1. url-pattern

    <url-pattern/>用来指定Servlet的访问路径,必须以/开头.

    • 可以在<servlet-mapping/>配置多个<url-pattern/>, 此时一个Servlet实例就绑定多个URL.
    • 可以在<url-pattern/>中使用通配符*,可以使一个Servlet绑定一组URL, 但*不能出现在中间位置,也不能只有*通配符, 另外, 通配符只是一种模糊匹配URL的方式,如果存在更具体的<url-pattern/>,那么会优先选择精确匹配.
  2. 配置在容器启动时创建Servlet实例

HelloServlet
com.fq.web.servlet.HelloServlet
1

<load-on-startup/>元素可以让容器在启动时就创建该Servlet实例(调用init()方法),注意<load-on-startup/>元素的值必须是>=0的整数,它代表容器启动时创建Servlet实例的顺序.


GenericService

GenericService抽象类实现了Servlet接口并完成以下工作:

1. 将init()方法中的ServletConfig赋给一个实例变量, 使他可以通过getServletConfig()来获取.
2. 为Servlet接口的所有方法提供默认实现.
3. 提供方法来包装ServletConfig.

  • Generic部分代码
public abstract class GenericServlet     implements Servlet, ServletConfig, java.io.Serializable{
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 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(); }}

HttpServlet

HttpServletGenericServlet的子类,它提供了对HTTP协议的支持.覆盖了GenericServletservice()方法,并新增了接受HttpServletRequest/HttpServletResponse参数的service()方法:

@Overridepublic void service(ServletRequest req, ServletResponse res)    throws ServletException, IOException{    HttpServletRequest  request;    HttpServletResponse response;    if (!(req instanceof HttpServletRequest &&            res instanceof HttpServletResponse)) {        throw new ServletException("non-HTTP request or response");    }    request = (HttpServletRequest) req;    response = (HttpServletResponse) res;    service(request, response);}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) {                // 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);    }}
  • 原始的service()将请求/响应向下转型为HttpServletRequest/HttpServletResponse, 并调用新的service(). 由于HttpServlet在新的service()方法中已经做了很多工作, 因此在继承HttpServlet实现自动以Servlet时, 则只需覆盖doGet()/doPost()等即可, 而没有必要覆盖service()(极少数情况需要覆盖doHead()等)

注意: Request/Response向下转型总会成功:因为在调用service()方法时,Servlet容器总会预计使用HTTP,从而直接创建并传递HttpServletRequest/HttpServletResponse实例.

  • HelloHttpServlet
/** * @author jifang. * @since 2016/4/20 19:48. */@WebServlet(name = "HelloHttpServlet", urlPatterns = "/hello_http_servlet.do")public class HelloHttpServlet extends HttpServlet {
@Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("doPost() ..."); } @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { System.out.println("doGet() ..."); }}

HttpServletRequest

对于每一个HTTP请求, Servlet容器会在调用service()方法时创建Request实例并传递给service形参, HttpServletRequest是Request在HTTP环境下的实例,其封装了有关请求的信息:

  • 封装请求头信息;
  • 封装请求正文数据(GET没有正文);
  • 提供请求转发/包含功能;
  • 作为域对象, 可以传递数据.

获取请求头

方法 描述
String getHeader(String name) Returns the value of the specified request header as a String.
Enumeration<String> getHeaderNames() Returns an enumeration of all the header names this request contains.
long getDateHeader(String name) Returns the value of the specified request header as a long value that represents a Date object.
Enumeration<String> getHeaders(String name) Returns all the values of the specified request header as an Enumeration of String objects.
int getIntHeader(String name) Returns the value of the specified request header as an int.
String getRemoteAddr() Returns the Internet Protocol (IP) address of the client or last proxy that sent the request.
String getMethod() Returns the name of the HTTP method with which this request was made, for example, GET, POST, or PUT.
String getContextPath() Returns the portion of the request URI that indicates the context of the request.
  • 获取请求来源
@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {    String referer = request.getHeader("Referer");    String userAgent = request.getHeader("User-Agent");    composeResponse(referer, userAgent, response);}private void composeResponse(String referer, String userAgent, HttpServletResponse response) throws IOException {    response.setHeader("Content-Type", "text/html;charset=utf-8");    PrintWriter writer = response.getWriter();    if (!Strings.isNullOrEmpty(referer)) {        writer.print("

来源地址: " + referer + "

"); } else { writer.print("

来自浏览器地址栏

"); } writer.print("

"); writer.print("

来源信息: " + userAgent + "

");}

获取请求参数

方法 描述
String getParameter(String name) Returns the value of a request parameter as a String, or null if the parameter does not exist.
Map<String,String[]> getParameterMap() Returns a java.util.Map of the parameters of this request.
Enumeration<String> getParameterNames() Returns an Enumeration of String objects containing the names of the parameters contained in this request.
String[] getParameterValues(String name) Returns an array of String objects containing all of the values the given request parameter has, or null if the parameter does not exist.
  • 获取微信请求消息
@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {    Element root;    String xml = request.getParameter("xml");    try {        if (!Strings.isNullOrEmpty(xml)) {            root = new SAXReader().read(new StringReader(xml)).getRootElement();        } else {            String data = CharStreams.toString(new InputStreamReader(request.getInputStream()));            root = new SAXReader().read(new StringReader(data)).getRootElement();        }    } catch (DocumentException | IOException e) {        LOGGER.error("parse wx xml error", e);        throw new RuntimeException();    }    // ...}

请求转发/包含

Request提供了getRequestDispatcher()来获取一个RequestDispatcher, 并由其提供请求转发/请求包含功能.

Request方法 描述
RequestDispatcher getRequestDispatcher(String path) Returns a RequestDispatcher object that acts as a wrapper for the resource located at the given path.

请求转发/请求包含都是由多个Servlet协作完成一个请求, 因此需要从一个Servlet中跳到另一个Servlet中:

RequestDispatcher方法 描述
void include(ServletRequest request, ServletResponse response) Includes the content of a resource (servlet, JSP page, HTML file) in the response.
void forward(ServletRequest request, ServletResponse response) Forwards a request from a servlet to another resource (servlet, JSP file, or HTML file) on the server.
  • 请求转发: 原Servlet只会保留设置的响应头信息.
  • 请求包含: 原Servlet既会保留响应头, 还会保留响应体内容.

注意: 请求转发时, 可能会因为原Servlet设置了过多的响应体内容导致抛出异常java.lang.IllegalStateException: Cannot forward after response has been committed


域对象传递数据

由于请求转发/请求包含都只是一次请求, 因此在多个Servlet之间都是共用一个Reqeust, 因此可以利用Request的在多个Servlet之间共享数据:

方法 描述
Object getAttribute(String name) Returns the value of the named attribute as an Object, or null if no attribute of the given name exists.
Enumeration<String> getAttributeNames() Returns an Enumeration containing the names of the attributes available to this request.
void setAttribute(String name, Object o) Stores an attribute in this request.
void removeAttribute(String name) Removes an attribute from this request.

HttpServletResponse

同Request, Servlet容器会在每次调用service()方法时创建Response实例并传递给service()形参, HttpServletResponse是Response绑定在HTTP环境下的实例, 其隐藏了将响应发送给浏览器的复杂性:

  • 设置响应状态码;
  • 设置响应头信息;
  • 设置响应正文;

设置响应状态码

方法 描述
void setStatus(int sc) Sets the status code for this response.
void sendError(int sc) Sends an error response to the client using the specified status code and clears the buffer.
void sendError(int sc, String msg) Sends an error response to the client using the specified status and clears the buffer.

关于状态码的描述, 详见HTTP协议部分介绍, 在此就不再赘述.

  • 响应404
@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {    // response.sendError(404, "nothing!!");    response.setStatus(404);}

设置响应头信息

方法 描述
void setHeader(String name, String value) Sets a response header with the given name and value.
void addHeader(String name, String value) Adds a response header with the given name and value.
void setIntHeader(String name, int value) Sets a response header with the given name and integer value.
void addIntHeader(String name, int value) Adds a response header with the given name and integer value.
void addDateHeader(String name, long date) Adds a response header with the given name and date-value.
void setDateHeader(String name, long date) Sets a response header with the given name and date-value.
void sendRedirect(String location) Sends a temporary redirect response to the client using the specified redirect location URL and clears the buffer.

关于HTTP响应头的描述, 详见HTTP协议部分介绍, 在此就不再赘述.

  • 设置禁用浏览器缓存(Cache-Control, pragma, expires)
@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {    response.setHeader("Cache-Control", "no-cache");    response.setHeader("pragma", "no-cache");    response.setDateHeader("expires", -1);}
  • 设置重定向(302, Location)
@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {    response.setStatus(HttpServletResponse.SC_MOVED_TEMPORARILY);    response.setHeader("Location", "http://www.baidu.com");}

HttpServletResponse还提供了另外一种重定向的方式, 直接使用sendRedirect()方法, 避免了以上的步骤:

@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {    response.sendRedirect("http://www.baidu.com");}

设置响应正文

Response提供了如下两个方法来获取输出流对象以响应HTTP正文内容

方法 描述
ServletOutputStream getOutputStream() Returns a ServletOutputStream suitable for writing binary data in the response.
PrintWriter getWriter() Returns a PrintWriter object that can send character text to the client.

OutputStream传输二进制数据流(字节数据), 常用作文件下载; Writer传输字符数据, 常用作响应HTTP正文内容(如HTML/XML等).

注意: 在一个请求中,不能同时使用这两个流, 否则会抛出IllegalStateException.

字符响应流
@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {    PrintWriter writer = response.getWriter();    writer.print("");    writer.print("

content

"); writer.print("");}
  • 缓冲区
    PrintWriter的默认缓冲区大小为8K, 因此当响应数据大小<8K时, 数据存放在缓冲区, 而不会立刻发送到浏览器, 直到Servlet执行结束,因此如果希望马上发送给浏览器, 需要调用Response的flushBuffer()方法手动刷新缓冲区.

ServletConfig

在容器初始化Servlet时, 会将一个ServletConfig实例传给init()方法,其封装了@WebServlet/部署描述符传递给Servlet的配置信息:

方法 描述
String getInitParameter(String name) Gets the value of the initialization parameter with the given name.
Enumeration<String> getInitParameterNames() Returns the names of the servlet’s initialization parameters as an Enumeration of String objects.
ServletContext getServletContext() Returns a reference to the ServletContext in which the caller is executing.
  • java
public void init(ServletConfig config) throws ServletException {    this.config = config;    Enumeration
names = config.getInitParameterNames(); while (names.hasMoreElements()) { String name = names.nextElement(); String value = config.getInitParameter(name); System.out.println(name + " -> " + value); }}
  • web.xml
HelloServlet
com.fq.web.servlet.HelloServlet
admin
com.fq
e-mail
zhujifang666@163.com

ServletContext

ServletConfig中提供了获取ServletContext的方法getServletContext(), ServletContext代表Servlet应用程序,且每个应用程序仅有一个ServletContext实例,其在容器启动时创建, 在容器关闭时销毁, 因此可以利用其在多个Servlet中传递数据.

所有域对象都有存取数据的功能,因为域对象内部有一个Map,用来存储数据,下面是ServletContext对象用来操作数据的方法:

方法 描述
void setAttribute(String name, Object object) Binds an object to a given attribute name in this ServletContext.
Object getAttribute(String name) Returns the servlet container attribute with the given name, or null if there is no attribute by that name.
Enumeration<String> getAttributeNames() Returns an Enumeration containing the attribute names available within this ServletContext.
void removeAttribute(String name) Removes the attribute with the given name from this ServletContext.

应用初始化参数

前面看到ServletConfig可以获取针对本Servlet的初始化参数,而利用ServletContext可以获取针对本应用程序的公共初始化参数:

方法 描述
String getInitParameter(String name) Returns a String containing the value of the named context-wide initialization parameter, or null if the parameter does not exist.
Enumeration<String> getInitParameterNames() Returns the names of the context’s initialization parameters as an Enumeration of String objects, or an empty Enumeration if the context has no initialization parameters.
  • web.xml
admin
feiqing
e-mail
zhujifang666@163.com
  • java
@Overrideprotected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {    ServletContext context = getServletContext();    String admin = context.getInitParameter("admin");    String email = context.getInitParameter("e-mail");    System.out.printf("admin: %s%n", admin);    System.out.printf("e-mail: %s%n", email);}

获取资源

可以使用ServletContext来获取Web应用下的资源路径/资源流等内容:

方法 描述
String getRealPath(String path) Gets the real path corresponding to the given virtual path.
URL getResource(String path) Returns a URL to the resource that is mapped to the given path.
InputStream getResourceAsStream(String path)` Returns the resource located at the named path as an InputStream object.
Set<String> getResourcePaths(String path) Returns a directory-like listing of all the paths to resources within the web application whose longest sub-path matches the supplied path argument.

转载于:https://www.cnblogs.com/itrena/p/5926899.html

你可能感兴趣的文章
Pyltp使用
查看>>
其他ip无法访问Yii的gii,配置ip就可以
查看>>
php做的一个简易爬虫
查看>>
x的x次幂的值为10,求x的近似值
查看>>
jquery获取html元素的绝对位置和相对位置的方法
查看>>
ios中webservice报文的拼接
查看>>
Power BI 报告的评论服务支持移动设备
查看>>
ACdream 1068
查看>>
HDU 2665 Kth number
查看>>
记叙在人生路上对你影响最大的三位老师
查看>>
002.大数据第二天
查看>>
python装饰器
查看>>
树上的路径
查看>>
【转载】TCP好文
查看>>
系统平均负载
查看>>
问题总结
查看>>
软件随笔
查看>>
Fast Poisson Disk Sampling
查看>>
Linux下SVN自动更新web [转]
查看>>
Openstack api 学习文档 & restclient使用文档
查看>>