Servlet详解

什么是Servlet

Servlet是Server Applet的简称,是用Java编写的服务器端程序,是JavaEE平台下的技术标准。其主要功能在于和浏览器交互并生成动态Web内容。狭义的Servlet是指Java语言实现的一个接口,广义的Servlet是指任何实现了这个Servlet接口的类,一般情况下,人们将Servlet理解为后者。

Servlet通常通过 HTTP(超文本传输协议)接收和响应来自 Web 客户端的请求。从原理上来讲,Servlet可以响应任何类型的请求,但绝大多数情况下Servlet只用来扩展基于HTTP协议的Web服务器。Servlet有三种实现方式:实现Servlet接口、继承抽象类GenericServlet、继承HttpServlet。

更简单的理解为:

Servlet是一种可以与用户进行交互的技术,它能够处理用户提交的HTTP请求并做出响应。简单来说servlet是运行在服务器上的java程序

Servlet程序可以完成JavaWeb应用程序中处理请求并发送响应的过程。通过Servlet技术,可以收集来自页面表单的用户输入,呈现来自数据库或者其他源的记录,还可以动态创建网页。Servlet是基于Java的、与平台无关的服务器端组件。

是JavaWeb最为核心的内容,它是Java提供的一门动态web资源开发技术

Servlet的作用:
通俗来讲servlet专门用来接收客户端的请求,专门接收客户端的请求数据,然后调用底层service处理数据并生成结果

          浏览器http请求------> tomcat服务器-------> 到达servlet-----> 执行doget,dopost方法------> 返回数据

<1>客户端发送请求到服务器端

<2>服务器将请求信息发送至Servlet

<3>Servlet生成响应内容并将其传给服务器

<4>服务器将响应返回给客户端

有哪些角色(在整个BS结构的系统当中,有哪些人参与进去了)

  • 浏览器软件的开发团队(浏览器软件太多了:谷歌浏览器、火狐浏览器、IE浏览器....)
  • WEB Server的开发团队(WEB Server这个软件也是太多了:Tomcat、Jetty、WebLogic、JBOSS、WebSphere....)
  • DB Server的开发团队(DB Server这个软件也是太多了:Oracle、MySQL.....)
  • webapp的开发团队(WEB应用是我们做为JavaWEB程序员开发的)

角色和角色之间需要遵守哪些规范,哪些协议

  • webapp的开发团队   和    WEB Server的开发团队  之间有一套规范: JavaEE规范之一Servlet规范。
  •     Servlet规范的作用是什么?
  •          解WEB Server   和   webapp耦合。
  •     Browser  和   WebServer之间有一套传输协议:HTTP协议。(超文本传输协议。)                     
  •     webapp开发团队  和  DB Server的开发团队之间有一套规范:JDBC规范。

Servlet规范是一个什么规范?

遵循Servlet规范的webapp,这个webapp就可以放在不同的WEB服务器中运行。(因为这个webapp是遵循Servlet规范的。)

Servlet严格意义上来说并不是一个简单的接口

Servlet规范包括什么呢?

遵循servlet规范的webapp,这个webapp就可以放在不同的web服务器中运行

    • 规范了哪些接口
    • 规范了哪些类
    • 规范了一个web应用中应该有哪些配置文件
    • 规范了一个web应用中配置文件的名字————固定的
    • 规范了一个web应用中配置文件存放的路径————固定的
    • 规范了一个web应用中配置文件的内容
    • 规范了一个合法有效的web应用它的目录结构应该是怎样的。
    • .....

Tomcat javaweb程序员都要遵守这个Servlet规范,这样Tomcat服务器和webapp才能解耦合

Servlet体系结构与Tomcat的关系

Servlet是Tomcat的一个组件,Servlet的功能需要依赖一个servlet-api.jar这个包是由Tomcat提供的,Tomcat在初始化Servlet时,首先读取web.xml文件,根据web.xml文件中的参数信息初始化ServletConfig、ServletContext对象,同时帮助我们创建HttpServletRequest和HttpServletResponse对象一并交给Servlet实例,此时,Servlet就具有了相关的功能。

开发一个带有servlet的webapp的步骤

  • 第一步:在webapps目录下新建一个目录,起名crm(这个crm就是webapp的名字)。当然,也可以是其它项目,比如银行项目,可以创建一个目录bank,办公系统可以创建一个oa。
    • 注意:crm就是这个webapp的根
  • 第二步:在webapp的根下(crm)新建一个目录:WEB-INF
    • 注意:这个目录的名字是Servlet规范中规定的,必须全部大写,必须一模一样。必须的必须。
  • 第三步:在WEB-INF目录下新建一个目录:classes
    • 注意:这个目录的名字必须是全部小写的classes。这也是Servlet规范中规定的。另外这个目录下一定存放的是Java程序编译之后的class文件(这里存放的是字节码文件)
  • 第四步:在WEB-INF目录下新建一个目录:lib
    • 注意:这个目录不是必须的。但如果一个webapp需要第三方的jar包的话,这个jar包要放到这个lib目录下,这个目录的名字也不能随意编写,必须是全部小写的lib。例如java语言连接数据库需要数据库的驱动jar包。那么这个jar包就一定要放到lib目录下。这Servlet规范中规定的。
  • 第五步:在WEB-INF目录下新建一个文件:web.xml
    • 注意:这个文件是必须的,这个文件名必须叫做web.xml。这个文件必须放在这里。一个合法的webapp,web.xml文件是必须的,这个web.xml文件就是一个配置文件,在这个配置文件中描述了请求路径和Servlet类之间的对照关系。
    • 这个文件最好从其他的webapp中拷贝。
<?xml version="1.0" encoding="UTF-8"?>

<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee
  https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd"
  version="5.0"
  metadata-complete="true">


</web-app>
  • 第六步:编写一个Java程序,这个小Java程序也不能随意开发,这个小java程序必须实现Servlet接口。
  • 第七步:编译我们编写的HelloServlet
    • 重点:你怎么能让你的HelloServlet编译通过呢?配置环境变量CLASSPATH
      CLASSPATH=.;C:\dev\apache-tomcat-10.0.12\lib\servlet-api.jar
    • 思考问题:以上配置的CLASSPATH和Tomcat服务器运行有没有关系?
      • 没有任何关系,以上配置这个环境变量只是为了让你的HelloServlet能够正常编译生成class文件。
  • 第八步:将以上编译之后的HelloServlet.class文件拷贝到WEB-INF\classes目录下。
  • 第九步:在web.xml文件中编写配置信息,让“请求路径”和“Servlet类名”关联在一起。
    • 这一步用专业术语描述:在web.xml文件中注册Servlet类。
      <?xml version="1.0" encoding="UTF-8"?>
      
      <web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee
        https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd"
        version="5.0"
        metadata-complete="true">
      
        <!--servlet描述信息-->
        <!--任何一个servlet都对应一个servlet-mapping -->
        <servlet>
          <servlet-name>fdsafdsagfdsafdsa</servlet-name>
          <!--这个位置必须是带有包名的全限定类名-->
          <servlet-class>com.bjpowernode.servlet.HelloServlet</servlet-class>
        </servlet>
      
        <!--servlet映射信息-->
        <servlet-mapping>
          <!--这个也是随便的,不过这里写的内容要和上面的一样。-->
          <servlet-name>fdsafdsagfdsafdsa</servlet-name>
          <!--这里需要一个路径-->
          <!--这个路径唯一的要求是必须以 / 开始-->
          <!--当前这个路径可以随便写-->
          <url-pattern>/fdsa/fd/saf/d/sa/fd/sa/fd</url-pattern>
        </servlet-mapping>
      
      </web-app>
  • 第十步:启动Tomcat服务器
  • 第十一步:打开浏览器,在浏览器地址栏上输入一个url,这个URL必须是:
  • 浏览器上编写的路径太复杂,可以使用超链接。(非常重要:html页面只能放到WEB-INF目录外面。
  • 以后不需要我们编写main方法了。tomcat服务器负责调用main方法,Tomcat服务器启动的时候执行的就是main方法。我们javaweb程序员只需要编写Servlet接口的实现类,然后将其注册到web.xml文件中,即可。
  • 总结一下:一个合法的webapp目录结构应该是怎样的?

 

webapproot
|------WEB-INF
|-----------classes(存放字节码)
|-----------lib(第三方jar包)
|-----------------web.xml(注册Servlet)
|-----------html
|-----------css
|-----------javascript
|-----------image
....

 

  • 浏览器发送请求,到最终服务器调用Servlet中的方法,是怎样的一个过程?
    • 用户输入URL,或者直接点击超链接:http://127.0.0.1:8080/crm/fdsa/fd/saf/d/sa/fd/sa/fd
    • 然后Tomcat服务器接收到请求,截取路径:/crm/fdsa/fd/saf/d/sa/fd/sa/fd
    • Tomcat服务器找到crm项目
    • Tomcat服务器在web.xml文件中查找/fdsa/fd/saf/d/sa/fd/sa/fd  对应的Servlet是:com.bjpowernode.servlet.HelloServlet
    • Tomcat服务器通过反射机制,创建com.bjpowernode.servlet.HelloServlet的对象。
    • Tomcat服务器调用com.bjpowernode.servlet.HelloServlet对象的service方法。

在Servlet中连接数据库,怎么做?

  • Servlet是Java程序,所以在Servlet中完全可以编写JDBC代码连接数据库。
  • 在一个webapp中去连接数据库,需要将驱动jar包(数据库的jar包)放到WEB-INF/lib目录下。(com.mysql.cj.jdbc.Driver 这个类就在驱动jar包当中。)

代码如下:
 

public class StudentServlet implements Servlet {
    @Override
    public void init(ServletConfig servletConfig) throws ServletException {

    }

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

    @Override
    public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException {


        response.setContentType("text/html");
        PrintWriter out=response.getWriter();
        //连接数据库
        Connection conn=null;
        PreparedStatement ps=null;
        ResultSet rs=null;
        try{
            //注册驱动
            Class.forName("com.mysql.cj.jdbc.Driver");
            //获取链接
            String url="jdbc:mysql://127.0.0.1:3306/test";
            String username="root";
            String password="123456";
            conn= DriverManager.getConnection(url,username,password);

            String sql="select id,name from yuangong";
            ps=conn.prepareStatement(sql);
            rs=ps.executeQuery();
            while(rs.next()){
                int id=rs.getInt("id");
                String name=rs.getString("name");
                out.print(id+","+name+"<br>");
            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }finally {
            if(rs!=null){
                try{
                    rs.close();
                }catch(SQLException e){
                    e.printStackTrace();
                }
            }
            if (ps != null) {
                try {
                    ps.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
            if (conn != null) {
                try {
                    conn.close();
                } catch (SQLException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    @Override
    public String getServletInfo() {
        return null;
    }

    @Override
    public void destroy() {

    }
}

执行原理

1.当服务器接收到客户端浏览器的请求后,会解析请求URL路径,获取访问的Servlet的资源路径

2.查找web.xml文件,是否有对应的<url-pattern>标签体内容

3.如果有,则在找到对应的<servlet-class>全类名

4,tomcat会将字节码文件加载进内存,并且创建其对象

5.调用其方法(暂且理解为调用service()方法)

Servlet生命周期

Servlet是由谁维护的?

Servlet对象的创建,对象上方法的调用,对象最终的销毁,Javaweb程序员是无权干预的。

Servlet对象的生命周期是由Tomcat服务器(WEB Server)全权负责的。

Servlet容器==WEB服务器==Tomcat服务器

如果是我们自己new的Servlet对象受WEB容器的管理吗?

我们自己new的Servlet对象是不受WEB容器管理的。

WEB容器创建的Servlet对象,这些Servlet对象都会被放到一个集合当中(HashMap),只有放到这个HashMap集合中的Servlet才能够被WEB容器管理,自己new的Servlet对象不会被WEB容器管理。(自己new的Servlet对象不在容器当中)

web容器底层应该有一个HashMap这样的集合,在这个集合当中存储了Servlet对象和请求路径之间的关系

服务器在启动的时候,Servlet对象有没有被创建出来(默认情况下)?

在Servlet中提供一个无参数的构造方法,启动服务器的时候看看构造方法是否执行。

经过测试得出结论:默认情况下,服务器在启动的时候Servlet对象并不会被实例化

这个设计是合理的。用户没有发送请求之前,如果提前创建出来所有的Servlet对象,必然是耗费内存的,并且创建出来的Servlet如果一直没有用户访问,显然这个Servlet对象是一个废物,没必要先创建。

怎么让服务器启动的时候创建Servlet对象呢?

在servlet标签中添加<load-on-startup>子标签,在该子标签中填写整数,越小的整数优先级越高。

取值必须是整数,如果是大于等于0的整数表示在服务器启动时就被创建并初始化

<servlet>
  <servlet-name>aservlet</servlet-name>
  <servlet-class>com.bjpowernode.javaweb.servlet.AServlet</servlet-class>
  <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
  <servlet-name>aservlet</servlet-name>
  <url-pattern>/a</url-pattern>
</servlet-mapping>

 Servlet对象生命周期

默认情况下服务器启动的时候AServlet对象并没有被实例化

用户发送第一次请求的时候,控制台输出了以下内容:

AServlet无参数构造方法执行了
AServlet's init method execute!
AServlet's service method execute!

根据以上输出内容得出结论:

  • 用户在发送第一次请求的时候Servlet对象被实例化(AServlet的构造方法被执行了。并且执行的是无参数构造方法。)
  • AServlet对象被创建出来之后,Tomcat服务器马上调用了AServlet对象的init方法。(init方法在执行的时候,AServlet对象已经存在了。已经被创建出来了。)
  • 用户发送第一次请求的时候,init方法执行之后,Tomcat服务器马上调用AServlet对象的service方法。

用户继续发送第二次请求,控制台输出了以下内容:

AServlet's service method execute!

根据以上输出结果得知,用户在发送第二次,或者第三次,或者第四次请求的时候,Servlet对象并没有新建,还是使用之前创建好的Servlet对象,直接调用该Servlet对象的service方法,这说明:

  • 第一:Servlet对象是单例的(单实例的。但是要注意:Servlet对象是单实例的,但是Servlet类并不符合单例模式。我们称之为假单例。之所以单例是因为Servlet对象的创建我们javaweb程序员管不着,这个对象的创建只能是Tomcat来说了算,Tomcat只创建了一个,所以导致了单例,但是属于假单例。真单例模式,构造方法是私有化的。)
  • 第二:无参数构造方法、init方法只在第一次用户发送请求的时候执行。也就是说无参数构造方法只执行一次。init方法也只被Tomcat服务器调用一次。
  • 第三:只要用户发送一次请求:service方法必然会被Tomcat服务器调用一次。发送100次请求,service方法会被调用100次。

关闭服务器的时候,控制台输出了以下内容:

AServlet's destroy method execute!

通过以上输出内容,可以得出以下结论:

Servlet的destroy方法只被Tomcat服务器调用一次。

Servlet中每个方法的介绍

无参构造方法可忽略

1.无参构造方法只执行一次

2.初始化方法init()只会执行一次,(启动Tomcat的时候默认是不执行的,在访问的时候才会执行)当Servlet第一次被请求时,Servlet容器会实例化这个Servlet,然后就会调用这个方法来初始化Servlet,但是这个方法在后续请求中不会在被Servlet容器调用,我们可以利用init()方法来执行相应的初始化工作。

3.服务方法service( ):每当请求Servlet时,Servlet容器就会调用这个方法。第一次请求时,Servlet容器会先调用init( )方法初始化一个Servlet对象出来,然后会调用它的service( )方法进行工作,但在后续的请求中,Servlet容器只会调用service方法了。每访问一次就调用(执行)一次,可以执行很多次。

4. 销毁方法destory():只执行一次,当要销毁Servlet时,Servlet容器就会调用这个方法,卸载应用程序或者关闭Servlet容器时,就会发生这种情况,一般在这个方法中会写一些清除代码。

destroy方法是在什么时候被调用的?

在服务器关闭的时候。
因为服务器关闭的时候要销毁AServlet对象的内存。
服务器在销毁AServlet对象内存之前,Tomcat服务器会自动调用AServlet对象的destroy方法。

destroy方法调用的时候,对象销毁了还是没有销毁呢?

destroy方法执行的时候AServlet对象还在,没有被销毁。destroy方法执行结束之后,AServlet对象的内存才会被Tomcat释放。

Servlet对象更像一个人的一生:

Servlet的无参数构造方法执行:标志着你出生了。

Servlet对象的init方法的执行:标志着你正在接受教育。

Servlet对象的service方法的执行:标志着你已经开始工作了,已经开始为人类提供服务了。

Servlet对象的destroy方法的执行:标志着临终。有什么遗言,抓紧的。要不然,来不及了。

当我们Servlet类中编写一个有参数的构造方法,如果没有手动编写无参数构造方法会出现什么问题?

    • 报错了:500错误。
    • 注意:500是一个HTTP协议的错误状态码。
    • 500一般情况下是因为服务器端的Java程序出现了异常。(服务器端的错误都是500错误:服务器内部错误。)
    • 如果没有无参数的构造方法,会导致出现500错误,无法实例化Servlet对象。
    • 所以,一定要注意:在Servlet开发当中,不建议程序员来定义构造方法,因为定义不当,一不小心就会导致无法实例化Servlet对象。

Servlet的无参数构造方法是在对象第一次创建的时候执行,并且只执行一次。init方法也是在对象第一次创建的时候执行,并且只执行一次。那么这个无参数构造方法可以代替掉init方法吗?

      • 不能。
      • Servlet规范中有要求,作为javaweb程序员,编写Servlet类的时候,不建议手动编写构造方法,因为编写构造方法,很容易让无参数构造方法消失,这个操作可能会导致Servlet对象无法实例化。所以init方法是有存在的必要的。

init、service、destroy方法中使用最多的是哪个方法?

      • 使用最多就是service方法,service方法是一定要实现的,因为service方法是处理用户请求的核心方法。

什么时候使用init方法呢?

      • init方法很少用。
      • 通常在init方法当中做初始化操作,并且这个初始化操作只需要执行一次。例如:初始化数据库连接池,初始化线程池....
      • 因为它只执行一次,说明一个Servlet在内存中只存在一个对象,Serlvet是单例的
        * 多个用户同时访问时,可能存在线程安全问题

*                 解决:尽量不要在Serlvet中定义成员变量。即使定义了成员变量,也不要修改值

什么时候使用destroy方法呢?

      • destroy方法也很少用。
      • 通常在destroy方法当中,进行资源的关闭。马上对象要被销毁了,还有什么没有关闭的,抓紧时间关闭资源。还有什么资源没保存的,抓紧时间保存一下。
      • Tomcat服务器在销毁AServlet对象之前会调用一次destory方法
      • destory方法在执行的时候,AServlet对象开启了一些资源,这些资源可能是流,可能是数据库连接
      • 那么,关闭服务器的时候,要关闭这些流和数据库连接的代码就可以写道destory方法当中

适配器

通过上面的代码我们发现,写一个Servlet类(它实现了Servlet接口),那就要吧这个接口的方法都写一遍,但实际上里面的方法中运用最多的,只有service方法,其他方法都只用了一次,如果可以只写service方法就好了,这时候就可以想到继承关系了,用接口的话,那么里面的方法都要写,可使用继承却不是,那么如果继承的父类是个抽象类,我们就只需要重写父类的抽象方法了,这也就是适配器(Adapter)

Servlet接口中的方法

public interface Servlet {
    void init(ServletConfig var1) throws ServletException;

    ServletConfig getServletConfig();

    void service(ServletRequest var1, ServletResponse var2) throws ServletException, IOException;

    String getServletInfo();

    void destroy();
}

思路:

我们可以写一个Servlet类(适配器)让他实现Servlet接口,然后把这个类里的service写成抽象方法(此时这个类是抽象类),我们把要用到的Servlet类继承这个适配器,那我们就只需要重写service方法了

编写一个GenericServlet类,这个类是一个抽象类,其中有一个抽象方法service。

GenericServlet实现Servlet接口。

GenericServlet是一个适配器。

以后编写的所有Servlet类继承GenericServlet,重写service方法即可。

示例:

//做抽象类的适配器————mainServlet
//不过这个是有标准通用的名字————GenericServlet
public abstract class mainServlet implements Servlet {


    @Override
    public void init(ServletConfig servletConfig) throws ServletException {

    }

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

    @Override
     public abstract void service
    (ServletRequest servletRequest, ServletResponse servletResponse) 
    throws ServletException, IOException ;



    @Override
    public String getServletInfo() {
        return null;
    }

    @Override
    public void destroy() {

    }
}
//继承适配器的类
public class testServlet extends mainServlet{
    public  void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException{
        System.out.println("正在处理用户请求,请稍后~");
    }

}
​
//记得配置xml文件
<servlet>
  <servlet-name>testServlet</servlet-name>
  <servlet-class>com.practice.javaweb.testServlet</servlet-class>
<--!上面是包名+类名-->

</servlet>
<servlet-mapping>
  <servlet-name>testServlet</servlet-name>
  <url-pattern>/testServlet</url-pattern>
</servlet-mapping>

​

那么,这个GenericServlet类还需不需要改造一下呢?

我们继承了这个类,里面的init方法包括其他的方法依然会执行,但是我们知道,init方法是用来实例化对象的,那么init这个方法是被谁调用的?是被Tomcat服务器调用的,那么我们又发现,这个init方法里面的参数列表,是一个ServletConfig对象,这个对象又是谁创建的呢?是谁传递过来的呢?都是Tomcat做的,Tomcat服务器先创建了ServletConfig对象,然后调用init方法,将ServletConfig对象传给了init方法

以下是还原的Tomcat服务器的伪代码

​
public class Tomcat {
          public static void main(String[] args){
              // .....
              // Tomcat服务器伪代码
              // 创建LoginServlet对象(通过反射机制,调用无参数构造方法来实例化LoginServlet对象)
              Class clazz = Class.forName("com.bjpowernode.javaweb.servlet.LoginServlet");
              Object obj = clazz.newInstance();
              
              // 向下转型
              Servlet servlet = (Servlet)obj;
              
              // 创建ServletConfig对象
              // Tomcat服务器负责将ServletConfig对象实例化出来。
              // 多态(Tomcat服务器完全实现了Servlet规范)
              ServletConfig servletConfig = new org.apache.catalina.core.StandardWrapperFacade();
              
              // 调用Servlet的init方法
              servlet.init(servletConfig);
              
              // 调用Servlet的service方法
              // ....
          }
}

​

  • 26
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器学习模型机器
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值