频道栏目
首页 > 程序开发 > 综合编程 > 其他综合 > 正文
Servlet(Servlet Applet)
2016-09-08 09:34:53         来源:OJZFY的博客  
收藏   我要投稿
/* GitHub stylesheet for MarkdownPad (https://markdownpad.com) */
/* Author: Nicolas Hery - https://nicolashery.com */
/* Version: b13fe65ca28d2e568c6ed5d7f06581183df8f2ff */
/* Source: https://github.com/nicolahery/markdownpad-github */

/* RESET
=============================================================================*/

html, body, p, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, embed, figure, figcaption, footer, header, hgroup, menu, nav, output, ruby, section, summary, time, mark, audio, video {
margin: 0;
padding: 0;
border: 0;
}

/* BODY
=============================================================================*/

body {
font-family: Helvetica, arial, freesans, clean, sans-serif;
font-size: 14px;
line-height: 1.6;
color: #333;
background-color: #fff;
padding: 20px;
max-width: 960px;
margin: 0 auto;
}

body>*:first-child {
margin-top: 0 !important;
}

body>*:last-child {
margin-bottom: 0 !important;
}

/* BLOCKS
=============================================================================*/

p, blockquote, ul, ol, dl, table, pre {
margin: 15px 0;
}

/* HEADERS
=============================================================================*/

h1, h2, h3, h4, h5, h6 {
margin: 20px 0 10px;
padding: 0;
font-weight: bold;
-webkit-font-smoothing: antialiased;
}

h1 tt, h1 code, h2 tt, h2 code, h3 tt, h3 code, h4 tt, h4 code, h5 tt, h5 code, h6 tt, h6 code {
font-size: inherit;
}

h1 {
font-size: 28px;
color: #000;
}

h2 {
font-size: 24px;
border-bottom: 1px solid #ccc;
color: #000;
}

h3 {
font-size: 18px;
}

h4 {
font-size: 16px;
}

h5 {
font-size: 14px;
}

h6 {
color: #777;
font-size: 14px;
}

body>h2:first-child, body>h1:first-child, body>h1:first-child+h2, body>h3:first-child, body>h4:first-child, body>h5:first-child, body>h6:first-child {
margin-top: 0;
padding-top: 0;
}

a:first-child h1, a:first-child h2, a:first-child h3, a:first-child h4, a:first-child h5, a:first-child h6 {
margin-top: 0;
padding-top: 0;
}

h1+p, h2+p, h3+p, h4+p, h5+p, h6+p {
margin-top: 10px;
}

/* LINKS
=============================================================================*/

a {
color: #4183C4;
text-decoration: none;
}

a:hover {
text-decoration: underline;
}

/* LISTS
=============================================================================*/

ul, ol {
padding-left: 30px;
}

ul li > :first-child,
ol li > :first-child,
ul li ul:first-of-type,
ol li ol:first-of-type,
ul li ol:first-of-type,
ol li ul:first-of-type {
margin-top: 0px;
}

ul ul, ul ol, ol ol, ol ul {
margin-bottom: 0;
}

dl {
padding: 0;
}

dl dt {
font-size: 14px;
font-weight: bold;
font-style: italic;
padding: 0;
margin: 15px 0 5px;
}

dl dt:first-child {
padding: 0;
}

dl dt>:first-child {
margin-top: 0px;
}

dl dt>:last-child {
margin-bottom: 0px;
}

dl dd {
margin: 0 0 15px;
padding: 0 15px;
}

dl dd>:first-child {
margin-top: 0px;
}

dl dd>:last-child {
margin-bottom: 0px;
}

/* CODE
=============================================================================*/

pre, code, tt {
font-size: 12px;
font-family: Consolas, “Liberation Mono”, Courier, monospace;
}

code, tt {
margin: 0 0px;
padding: 0px 0px;
white-space: nowrap;
border: 1px solid #eaeaea;
background-color: #f8f8f8;
border-radius: 3px;
}

pre>code {
margin: 0;
padding: 0;
white-space: pre;
border: none;
background: transparent;
}

pre {
background-color: #f8f8f8;
border: 1px solid #ccc;
font-size: 13px;
line-height: 19px;
overflow: auto;
padding: 6px 10px;
border-radius: 3px;
}

pre code, pre tt {
background-color: transparent;
border: none;
}

kbd {
-moz-border-bottom-colors: none;
-moz-border-left-colors: none;
-moz-border-right-colors: none;
-moz-border-top-colors: none;
background-color: #DDDDDD;
background-image: linear-gradient(#F1F1F1, #DDDDDD);
background-repeat: repeat-x;
border-color: #DDDDDD #CCCCCC #CCCCCC #DDDDDD;
border-image: none;
border-radius: 2px 2px 2px 2px;
border-style: solid;
border-width: 1px;
font-family: “Helvetica Neue”,Helvetica,Arial,sans-serif;
line-height: 10px;
padding: 1px 4px;
}

/* QUOTES
=============================================================================*/

blockquote {
border-left: 4px solid #DDD;
padding: 0 15px;
color: #777;
}

blockquote>:first-child {
margin-top: 0px;
}

blockquote>:last-child {
margin-bottom: 0px;
}

/* HORIZONTAL RULES
=============================================================================*/

hr {
clear: both;
margin: 15px 0;
height: 0px;
overflow: hidden;
border: none;
background: transparent;
border-bottom: 4px solid #ddd;
padding: 0;
}

/* TABLES
=============================================================================*/

table th {
font-weight: bold;
}

table th, table td {
border: 1px solid #ccc;
padding: 6px 13px;
}

table tr {
border-top: 1px solid #ccc;
background-color: #fff;
}

table tr:nth-child(2n) {
background-color: #f8f8f8;
}

/* IMAGES
=============================================================================*/

img {
max-width: 100%
}

 

 

Servlet(Servlet Applet)
server +applet ==>servlet 服务器端小应用程序。

 

背景知识

既然是服务器端技术,我们应该知道服务器是有硬件服务器,软件服务器,硬件可以看成是高配置的电脑 软件的服务器,今天我们就用一下tomcat: 1)IIS 2)Apache 3)Tomcat

通常的动态的网页技术

1)CGI(Common Gate Interface)
2) API常用的用(NSAPI,ISAPI)
3) ASP(Active Server Page)
4) PHP(Porsonal Home Page)
5) JSP/Servlet(Java Server Page)

Servet 简介

1)Servlet是服务器小应用程序。
2)用来完成B/S架构下,客户端请求的响应的处理
3)平台独立,性能优良,能以线程方式运行
4)Servlet的API为Servlet提供了
5)Servlet一般在容器中运行
6)Servlet是一种特殊的java类,jsp本质上就是Servlet,所以jsp也是java类。
7)常见的Servlet容器
    1.Tomcat(其下载,安装,运行)。
    https://tomcat.apache.org/
8)运行方式
    a.startup.bat/shurtdown.bat
    b.catalina.bat start /stop

Tomcat启动异常:

1)启动bin下面的startup.bat一闪没了,一般是JAVA_HOME的没有配置好。
2)找不到主类org.apatch...BootStrap.jar 一般是tomcat 文件没有下载全。
3)异常UnsupportedClassVersionError错误,一般是jdk版本和tomcat版本不一致。

Tomcat下面的常见目录

1)bin 二进制可执行文件和脚步
2)lib 所有的.jar文件 servlet.api.jar
3)logs 日志文件
4)webapps web项目部署的地方
5)work  编译后的文件的所在地方。
6)common Catalina本身和web应用可加装的类目录
7)temp

Tomcat配置文件

a.conf/server.xml 服务器的主配置文件
b.conf/web.xml定义所有web应用的配置(缺省的Servlet定义和MIME类型的定义)
c.conf/tomcat-user.xml定义tomcat用户的信息。

HTTP协议的原理

.HTTP(Hyper Text Transfer Prototocal)是超文本传输协议。
.HTTP消息包括客户端向服务器的请求信息和服务器向客户端的响应的消息。
.浏览器和服务器的信息交换过程:
    .建立连接
    .发送请求信息
    .回应响应信息
    .关闭连接
.HTTP协议是一个无状态的协议
.HTTP1.1支持持连接,一次连接可以发送多次请求。

给大家回归一下HTTP请求的基本知识:

*一个完整的请求消息包括*
.一个请求行,若干消息头,实体内容。
*请求行格式:*
.请求方式,资源路径,http版本号
*一个典型的Get请求:*
*一个完整的响应的消息包括:*
.状态行 一个或者多个应答头,响应实体
*状态行格式:*
.http版本号 状态码,原因叙述
.状态码:200(一切正常),404(所请求资源不存在),500(服务器内部程序错误。)

http的总结:

.请求响应式
.无状态的协议(对事务的处理没有记忆性)。
.http1.1版本支持可持续连接。
.速记“三三原则”

Servlet第一个应用程序

/**
 * 一,创建一个web项目
 *新建一个java类extends HttpServlet 重写service 方法。
 *输出一句话。
 *在webRoot/web-inf/web.xml中建立url映射。
 *
 *
 *  
 *  
 *
 *
 *  
 *  
 *
 *
 *将项目部署到服务器上
 *  1)servers(Tomcat)-->右键Add deployment
 *  2)Deploy上找到项目添加到服务器上。
 *访问:https://localhost:8080/project名/HiServlet
 * @author Peter Teacher
 */

    public class HiServlet extends HttpServlet{
        @Override
        protected void service(HttpServletRequest req, HttpServletResponse resp)
                throws ServletException, IOException {
            System.out.println("Hi Servlet!");
        }       

web.xml配置文件

    

    
        HiServlet
        com.bjsxt.servlet.HiServlet
    
    
        HiServlet
        /HiServlet.do
    
    
        index.jsp
    

form表单的知识

单例模式:

.恶汉式

    public class Single {
        public static Single ss = new Single();//恶汉式
        /**
         * 构造器私有
         */
        private Single() {
            System.out.println("Single.Single() 我被创建了" + new Date().getTime());
        }
        /**
         * 实例化返回实例
         * @return
         */
        public static Single newInstance() {
            return ss;
        }
    }

*懒汉式:*

public class LanSingle {
    public static LanSingle ss = null;// 懒汉式
    /**
     * 构造器私有
     */
    public LanSingle() {
        System.out.println("LanSingle.LanSingle() 我被创建了!!"
                + new Date().getTime());
    }
    /**
     * 构造实例返回
     */
    public static LanSingle newInstance() {
        if (ss == null) {
            synchronized (LanSingle.class) {
                if (ss == null) {
                    ss = new LanSingle();
                }
            }
        }
        return ss;
    }
}

Servlet 生命周期

Servlet 是一个对象支持多线程访问。
        默认是懒汉式
    10可以配置成恶汉式
1.创建对象
    创建一次,第一次被访问的时候
2.初始化
    初始化一次,第一次被访问的时候
3.接受请求
 当可用户端发送请求的时候,服务器会自动New一个线程默认去创建对象,并调用service方法。
    a.405问题,不要调用父类的doGet和doPost方法
    b.慎用成员变量,资源不安全,优先使用局部变量。
4.销毁对象。
  服务器被关闭时候自动销毁。

public class LifeServlet extends HttpServlet {
    public int count=0;
    public LifeServlet() {
        System.out.println("LifeServlet.LifeServlet()我被创建了");
    }

    @Override
    public void init() throws ServletException {
        System.out.println("LifeServlet.init()我被初始化了 无参");
    }
    @Override
    public void init(ServletConfig config) throws ServletException {
        System.out.println("LifeServlet.init()有参");;
        init();
    }
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) {
        System.out.println("LifeServlet.service() 分发");
        //System.out.println(count++);
        PrintWriter out=null;
        try {
            out = resp.getWriter();
        } catch (IOException e) {
            e.printStackTrace();
        }
        out.print(count++);
    }
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
    }
    @Override
    public void destroy() {
        System.out.println("LifeServlet.destroy()我被销毁了!");
    }
}

Servlet的配置的细节

1.工程名--部署后的名默认是相同的。
2.里面的可以增加配置变为恶汉式。load-on-stardup
3./HiServlet
  *.abc
  /bbb/*
  /ccc/*.abc错误的配置

HttpServletRequest对象

客户端的请求信息可以通过请求对象获得,常见的方法如下:

 请求行信息

    请求方式+url+版本号

private void getReqline(HttpServletRequest request) {// 请求行的信息
        System.out.println("HiReqServlet.getReqline() 请求方式>>"
                + request.getMethod());
        System.out.println("HiReqServlet.getReqline() url>>"
                + request.getRequestURL());
        System.out.println("HiReqServlet.getReqline() uri>>"
                + request.getRequestURI());
        System.out.println("HiReqServlet.getReqline(get方式的请求参数)"
                + request.getQueryString());
        System.out.println("HiReqServlet.getReqline() 版本>>"
                + request.getProtocol());
        System.out.println("HiReqServlet.getReqline(webapp的名字)"
                + request.getContextPath());
    }

  若干消息头

private void getReqHeader(HttpServletRequest request) {
        System.out.println("HiReqServlet.getReqHeader() 若干消息头");
        System.out.println("HiReqServlet.getReqHeader() 代理:"
                + request.getHeader("User-agent"));
        System.out.println("HiReqServlet.getReqHeader() 请求参数:"
                + request.getParameter("uname"));
        System.out.println("HiReqServlet.getReqHeader() 所有的头信息:"
                + request.getParameterNames());
        Enumeration names = request.getHeaderNames();
        while (names.hasMoreElements()) {
            String ele = names.nextElement();
            System.out.println(ele + ":" + request.getHeader(ele));
        }
        System.out.println("---------------------------------");
        Enumeration parames = request.getParameterNames();
        while (parames.hasMoreElements()) {
            String str = parames.nextElement();
            System.out.println(str);
        }
}   

***实体内容***

private void getRequestBody(HttpServletRequest request) {
        //一个属性对应一个值的(null和空字符串的区别很大)
        String name = request.getParameter("name");
        String age = request.getParameter("age");
        String school = request.getParameter("school");
        System.out.println(name+":"+age+":"+school+".");
        //一个属性对应多个值的
        System.out.println("----------一对多的情况---------");
        String[] fav = request.getParameterValues("school");
        if(fav!=null && fav.length>0){
            for (int i = 0; i < fav.length; i++) {
                System.out.println("HiReqServlet.getRequestBody():"+fav[i]);
            }
        }
        System.out.println("-------getParameterMap()-----------");
        Map map = request.getParameterMap();
        Set keyset = map.keySet();
        Iterator iter = keyset.iterator();
        while (iter.hasNext()) {
            String str =  iter.next();
            System.out.println(str+":"+map.get(str));
        }
        System.out.println("----------getParameterNames()-----------------------");
        Enumeration enumer = request.getParameterNames();
        while (enumer.hasMoreElements()) {
            String string = (String) enumer.nextElement();
            System.out.println(string+":"+request.getHeader(string));
        }
        System.out.println("------------getHeaderNames()-------------------------------------------");
        Enumeration hn = request.getHeaderNames();
        while (hn.hasMoreElements()) {
            String string = (String) hn.nextElement();
            System.out.println(string+":"+request.getHeader(string));
        }
    }

***网络消息***

    private void getRequestNet(HttpServletRequest request) {
        // 网络信息分为客户端,服务器
        System.out.println("HiReqServlet.getRequestNet()"
                + request.getRemoteAddr() + ":" + request.getRemotePort());
        System.out.println("HiReqServlet.getRequestNet()"
                + request.getLocalAddr() + ":" + request.getLocalPort());
    }

登录与注册

1.相应数据拼接的文本。
2.连接数据。

login.jsp源码


用户登录页面

用户名
密码

服务器端的跳转技术之请求重定向:

重定向

/**
 * @author Peter Teacher 
 * 1.地址栏是否发生变化---》发生变化 
 * 2.一共发送了几次请求---》两次请求
 * 3.是否可以访问外部资源--》可以 
 * 4.重定向的后代码是否可以执行--》可以执行
 */
public class HiRedirect extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        System.out.println("HiRedirect.service(111)");
        resp.sendRedirect("hello.jsp");
        return;
    }
}

重定向的内部执行图

请求转发

请求转发的案例

/**
 * @author Peter Teacher
 * 请求转发
 *  1.地址栏是否发生变化--》没有变化
 *  2.请求转发一共几次请求--》一次请求
 *  3.请求转发后的代码是否可以执行--》可以执行
 *  4.请求转发是否可以访问外部资源--》不可以访问外部资源
 *      请求转发与重定向的选择
 *          1)内部资源优先考虑请求转发(一次请求类似于方法的调用效率高)
 *          2)外部资源只能选择重定向。
 *          3)用request作用域传递值,只能选择请求转发。
 *  作用域(requet)
 *      内部模仿map  key --value
 *  生命周期
 *      一次请求之间
 *  作用范围
 *      所有转发过的servlet
 *  三个方法
 *  set,get,remove方法。
 *
 */
public class HiForward01 extends HttpServlet {
    @Override
    protected void service(HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException {
        // 请求转发
        System.out.println("HiForward01.service()"
                + new Date().toLocaleString());
        request.setAttribute("errorMsg","请核实用户名和密码是否匹配");
        request.getRequestDispatcher("HiForward02.do").forward(request,
                response);
    }
}

请求转发的执行流程

学生作业题注册页面

回话跟踪技术Cookie

1.http请求响应式
2.无状态性
3.http1.1后支持持续连接
4.Cookie依赖客户端,瞬时cookie,支持化cookie

public class HiCookieCreate extends HttpServlet {
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        // 创建cookie
        Cookie computerCookie = new Cookie("comptuer", "lenovo");
        Cookie mouserCookie = new Cookie("mouser", "raser");
        Cookie keyCookie = new Cookie("key", "double fly bird");
        // 设置cookie失效时间(决定了cookie的存活时间)
        computerCookie.setMaxAge(2 * 24 * 60 * 60);
        // 设置cookie路径(决定了什么时候cookie提交给服务器)。
        keyCookie.setPath(req.getContextPath() + "/key");

        resp.addCookie(keyCookie);
        resp.addCookie(computerCookie);
        resp.addCookie(mouserCookie);
    }
}

回话跟踪技术Session

session:(服务器端)
    .适合保存大量的数据
    .安全
    .效率高
    .Session跟踪机制中需要cookie来保存和传递sessionId
cookie:(客户端)
    .不适合保存大量的数据
    .不安全
    .效率低

/**
 * session 也是一个作用域
 * 
 * 生命周期
 *    一次回话(表面上一次浏览器的打开与关闭)
 *      开始:客户端和服务器建立连接并申请了Session对象。
 *      结束:客户丢失session的ID
 *          服务器重启或者session超过了活动周期。
 * 作用范围:
 *      所有的servlet
 * 方法
 * set,get,remove;
 * 作用:
 *  存储信息
 * 其实session 也类似于map  key --value
 * 有cookie来保留session的id, session 来管理对象。
 * 
 * cookie 与 session 如何抉择呢?
 * 
 *  客户端:cookie 存储数据量小,不安全,位于客户端,效率高
 *  服务器端:session 存储数据量大,安全,位于服务器端,效率低。
 * @author Peter Teacher
 */
public class HiSession extends HttpServlet{
    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        //创建Session(若干有session就直接用,若没有就创建一个新的)
        HttpSession session = req.getSession();
        System.out.println("HiSession.service(session的ID 是唯一标识的属性)"+new Date().getTime()+"---"+session.getId());
        //整个web的session 的失效时间 服务器内部默认的30分钟,也可以直接让session失效。
        /**
         *     
              30
              
         */
        //当前回话的sessions失效1 正整数到时间失效,0和负数永不失效。
        session.setMaxInactiveInterval(10);
        System.out.println(session.isNew()+"<<<<<<<");
        //session 失效2 立马失效
        //session.invalidate();
        //System.out.println(session.isNew()+"---------");
    }
}   

ServletConfig

一般用于处理该servlet的配置文件的配置信息(一般了解内容)

.常见有这几个方法:
ServletConfig sc=this.getServletConfig();
sc.getInitParameter(uname);
sc.getServletName();
sc.getInitParameterNames();

ServletContext

.一个web应用只有一个ServletContext对象,所有的Servlet都共享这个servletContext对象,又称为Application 对象,也是一个作用域。 .空间:最广,被所有的Servlet共享 .时间:最长,从web应用被加载到被卸载都有效。

/**
 * ServletContext 作用域
 *  生命周期
 *      项目的加载到卸载
 *  作用范围
 *      项目下所有的Servlet 
 *  常用方法
 *  setAttribute 
 *  getAttribute
 *  removeAttribute
 *  三大作用域:
 *      request(一次性的数据,登录,显示而已)
 *          周期:一次请求
 *          所有被请求转发过的Servlet
 *      session(购物和某一个用户相关的信息)
 *          周期:一次回话
 *          所有的Servlet
 *      application(全局的配置信息)
 *          周期:项目的加载与卸载
 *          所有的servlet
 * @author Peter Teacher
 */
public class HiContext extends HttpServlet {
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        //获取ServletContenxt的三种方式
        ServletContext sc1 = this.getServletContext();
        ServletContext sc2 = this.getServletConfig().getServletContext();
        ServletContext sc3 = request.getSession().getServletContext();
        //一个项目就一application作用域
        System.out.println(sc1==sc2);
        System.out.println(sc1==sc3);
        //获取全局参数值
        System.out.println(sc1.getInitParameter("uname"));
        //获取真实路径
        System.out.println(sc1.getRealPath("/"));
        //读取webRoot下面的文件
        InputStream is = sc1.getResourceAsStream("file.txt");
        System.out.println(is.available());
    }
}

乱码问题

请求乱码:

    post 方式
        request.setCharactorEncoding="utf-8"
    get  方式
        EncodingCompleter(String)了解
        useBodyEncodingForURI="utf-8"
        request.setCharactorEncoding="utf-8"

响应乱码:

    resp.setCharacterEncoding("utf-8");
    resp.setHeader("content-type","text/html;charset=utf-8");
    resp.setContextType("text/html;charset=utf-8");

/**
 * 乱码问题: 要宏观上把控一下, 
 *  项目的编码 
 *  页面的编码 
 *  数据库的编码 
 *  浏览器的编码 
 * 乱码的原因是编码不统一造成的!
 * 
 * @author Peter Teacher 
 * 请求乱码: post方式:
 *               request.setCharacterEncoding("utf-8");
 *         get方式:
 *               encodeComplente(String)---了解
 *               request.setCharacterEncoding("utf-8"); 
 *               useBodyEncodingForURI="true";
 *         响应乱码:
                response.setCharacterEncoding("utf-8");响应的编码集的设置
 *              response.setHeader("content-type","text/html;charset=utf-8")
 *             //response.setContentType("text/html;charset=utf-8"); new
 *             String((str.getByte("iso-8859-1")),"utf-8");
 */
public class HiServlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest request,
            HttpServletResponse response) throws ServletException, IOException {
        // 获取提交信息
        //request.setCharacterEncoding("utf-8");
        String name = request.getParameter("name");
        String nicename = request.getParameter("nicename");
        nicename=new String((nicename.getBytes("iso-8859-1")),"utf-8");
        System.out.println(name + "----" + nicename);
        // 响应乱码的问题
        response.setCharacterEncoding("utf-8");
        // response.setHeader("content-type","text/html;charset=utf-8");
        response.setContentType("text/html;charset=utf-8");
        PrintWriter out = response.getWriter();
        out.println("新的一年开始了" + Math.random());
        System.out.println("---------------------------");
    }
}



点击复制链接 与好友分享!回本站首页
上一篇:(18)Struts2_通用标签
下一篇:TQ210 —— LCD
相关文章
图文推荐
点击排行

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训 | 举报中心

版权所有: 红黑联盟--致力于做实用的IT技术学习网站