简介Servlet

news2024/11/28 19:39:14

目录

一、maven中心库

二、简介Servlet

三、实现Servlet动态页面

1、创建一个maven项目

2、引入依赖 

3、创建目录结构 

 4、编写Servlet代码

5、打包 

6、部署 

7、验证程序 

四、Servlet的运行原理

五、Tomcat伪代码 

1、Tomcat初始化

a、让Tomcat先从指定的目录中找到要加载的Servlet类

b、 根据类加载结果,给这些类创建Servlet实例

c、实例创建完成之后,调用当前Servlet实例的init方法。

d、创建TCP socket,监听8080端口等待有客户端来连接

e、退出循环,依次调用调用Servlet的destroy的方法 

2、Tomcat处理请求 

3、Servlet 的 service 方法的实现 

六、Servlet关键API 

1、HttpServlet类 

2、HttpServletRequest 类

3、HttpServletResponse类


一、maven中心库

maven中心库是一个“工程管理/构建工具”,其核心功能有:

  • 管理依赖;
  • 构建/编译,这个过程会调用JDK;
  • 打包,就是可以将Java代码打包成jar文件或者war文件。

maven中心库能够将这些操作串起来。

可以不用下载安装maven,idea中内置了maven中心库。

二、简介Servlet

Servlet 是一种实现动态页面的技术. 是一组 Tomcat 提供给 API, 帮助简单高效的开发一 个 web app.

动态页面就是每次用户输入的参数不同构造出的输出结果不同。例如百度的搜素页面,每次搜索的关键词不同得到的页面结果也不同。

三、实现Servlet动态页面

1、创建一个maven项目

创建一个项目,选择maven,点击next选择文件存储的路径即可。 

2、引入依赖 

进入maven库 https://mvnrepository.com下载servlet依赖,选择与自己JDK和tomcat匹配的版本。 

将对应的maven内容引入到创建的maven项目中的pom.xml中,并需要引入在depencies标签中。

   

在刚开始引入时会出现报红,但是当依赖自动下载完成之后字体就会恢复正常。

3、创建目录结构 

maven虽然已经有了一些目录:

  • src 表示源代码所在的目录。
  • main/java 表示源代码的根目录.,后续创建 .java 文件就放到这个目录中.
  • main/resources 表示项目的一些资源文件所在的目录. 此处暂时不关注.
  • test/java 表示测试代码的根目录. 此处暂时不关注。

但是还是不足以支撑写一个Servlet项目,还需要手动创建一些目录和文件。

web.xml文件内容如下:

<!DOCTYPE web-app PUBLIC
        "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
        "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
    <display-name>Archetype Created Web Application</display-name>
</web-app>

 4、编写Servlet代码

在main/java目录下创建HelloServlet类,该类继承HttpServlet,然后重写了doGET方法。

@WebServlet("/hello")
public class HelloServlet  extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("hello world");
        resp.getWriter().write("hello world");
    }
}
  • doGet方法要做的工作就是根据请求计算出响应,这个方法在Tomcat收到一个HTTP GET请求的时候就会被Tomcat调用,也是一个回调函数。
  • 传入的HttpServletRequest代表的是一个HTTP请求,HttpServletResponse代表的是一个HTTP响应。
  • 在这个类上方加上 @WebServlet("/hello") 注解, 表示 Tomcat 收到的请求中, 路径为 /hello 的请求才会调用 HelloServlet 这个类的代码. (这个路径未包含 Context Path)。
  • resp.getWriter() 会获取到一个流对象, 通过这个流对象就可以写入一些数据, 写入的数据会被 构造成一个 HTTP 响应的 body 部分, Tomcat 会把整个响应转成字符串, 通过 socket 写回给浏览器.

这里就体现出如果一个类要被TomCat调用需要满足如下条件:

  • a) 创建的类需要继承自 HttpServlet
  • b) 这个类需要使用 @WebServlet 注解关联上一个 HTTP 的路径
  • c) 这个类需要实现 doXXX 方法.

5、打包 

需要先修改pom.xml,打包成一个war包,因为默认是jar包,再设置打包的文件名称。

  <!-- 打的包是一个war包,默认是jar包 -->
    <packaging>war</packaging>
    <build>
        <!-- 表示打出的war包的名称-->
        <finalName>hello</finalName>
    </build>

然后双击package 进行打包。

 打包成功,并在target文件夹下生成了hello.war文件。

6、部署 

将上一步生成的hello.war文件拷贝到Tomcat的webapps目录下。

7、验证程序 

打开Tomcat服务器,使用127.0.0.1:8080/hello/hello在浏览器中进行访问。

绿色代表第一级目录,叫做Context Path,就是刚才拷贝到webapps目录下的war包文件名称。 

紫色代表第二级目录,叫做Servlet Path,是刚才创建的HelloServlet上面的@WebServlet("/hello")注解名称。

如果对代码进行了如下修改:

 resp.getWriter().write("hello world"+System.currentTimeMillis());

就需要再将5、6、7 再重复一遍,新修改的代码再次访问时才会生效。

这就引入了idea中的是smart Tomcat插件方便我们进行操作。

安装SmartTomcat插件:

 下载完成后进行apply应用。

然后点击运行 

 

出现如下信息表示成功: 然后再次在浏览器中访问即可:

 

每次刷新,时间戳也会发生改变。 

四、Servlet的运行原理

Servlet是属于上层建筑,下面的传输层、网络层、数据链路层和物理层属于经济基础。

Servlet是Tomcat提供的API,但是Tomcar其实也只是一个应用程序,是运行在用户态的普通进程,然后用户写代码(根据请求计算响应),通过Servlet和Tomcat进行交互,然后Tomcat进一步和浏览器之间进行网络传输。

                    

具体的过程也可以参考下图:

接收请求:用户会在浏览器输入一个URL,然后浏览器就出构造出相应的HTTP请求,这个HTTP请求会经过网络协议栈逐层封装成二进制的比特流,最后经过物理层的硬件设备转换成光信号或者电信号传输出去,然后这些信号再经过互联网的一系列网络设备到达服务器主机,服务器主机经过逐层分用还原得到HTTP请求交给Tomcat进行处理,然后利用HTTP请求的格式进行解析。根据 请求中的 Context Path 确定一个 webapp, 再通过 Servlet Path 确定一个具体的 类. 再根据当前请 求的方法 (GET/POST/...), 决定调用这个类的 doGet 或者 doPost 等方法. 此时我们的代码中的 doGet / doPost 方法的第一个参数 HttpServletRequest 就包含了这个 HTTP 请求的详细信息。

返回响应:doGet / doPost 执行完毕后, Tomcat 就会自动把 HttpServletResponse 这个我们刚设置 好的对象转换成一个符合 HTTP 协议的字符串, 通过 Socket 把这个响应发送出去.

此时响应数据在服务器的主机上通过网络协议栈层层 封装 , 最终又得到一个二进制的 bit , 通过 物理层硬件设备转换成光信号/ 电信号传输出去 . 这些承载信息的光信号/ 电信号通过互联网上的一系列网络设备 , 最终到达浏览器主机,收到这些光信号/ 电信号 , 又会通过网络协议栈逐层进行 分用 , 层层解析 , 最终还原成 HTTP 响应 , 并交给浏览器处理 . 浏览器也通过 Socket 读到这个响应 ( 一个字符串 ), 按照 HTTP 响应的格式来解析这个响应 . 并且把 body 中的数据按照一定的格式显示在浏览器的界面上 .

五、Tomcat伪代码 

通过 " 伪代码 " 的形式描述了 Tomcat 初始化 / 处理请求 两部分核心逻辑 .

1、Tomcat初始化

a、让Tomcat先从指定的目录中找到要加载的Servlet类

在前面部署的时候将Servlet代码编译成.class文件,然后打包成war包,并且拷贝到webapps文件夹里面,Tomcat就会从webapps里找到.class文件对应的Servlet类,然后根据需要加载 

b、 根据类加载结果,给这些类创建Servlet实例

// 这里要做的的是实例化出所有的 Servlet 对象出来;
        for (Class<Servlet> cls : allServletClasses) {
            // 这里是利用 java 中的反射特性做的
           // 实际上还得涉及一个类的加载问题,因为我们的类字节码文件,是按照约定的
            // 方式(全部在 WEB-INF/classes 文件夹下)存放的,所以 tomcat 内部是
            // 实现了一个自定义的类加载器(ClassLoader)用来负责这部分工作。
            
            Servlet ins = cls.newInstance();
            instanceList.add(ins);
       }

c、实例创建完成之后,调用当前Servlet实例的init方法。

 // 调用每个 Servlet 对象的 init() 方法,这个方法在对象的生命中只会被调用这一次;
        for (Servlet ins : instanceList) {
            ins.init();
       }

d、创建TCP socket,监听8080端口等待有客户端来连接

// 利用我们之前学过的知识,启动一个 HTTP 服务器
        // 并用线程池的方式分别处理每一个 Request
        ServerSocket serverSocket = new ServerSocket(8080);
        // 实际上 tomcat 不是用的固定线程池,这里只是为了说明情况
        ExecuteService pool = Executors.newFixedThreadPool(100);
        
        while (true) {
            Socket socket = ServerSocket.accept();
            // 每个请求都是用一个线程独立支持,这里体现了我们 Servlet 是运行在多线程环境下的
            pool.execute(new Runnable() {
               doHttpRequest(socket); 
           });
       }

e、退出循环,依次调用调用Servlet的destroy的方法 

 // 调用每个 Servlet 对象的 destroy() 方法,这个方法在对象的生命中只会被调用这一次;
        for (Servlet ins : instanceList) {
            ins.destroy();
       }

2、Tomcat处理请求 

class Tomcat {
    void doHttpRequest(Socket socket) {
        // 参照我们之前学习的 HTTP 服务器类似的原理,进行 HTTP 协议的请求解析,和响应构建
        HttpServletRequest req = HttpServletRequest.parse(socket);
        HttpServletRequest resp = HttpServletRequest.build(socket);
        
        // 判断 URL 对应的文件是否可以直接在我们的根路径上找到对应的文件,如果找到,就是静态
内容
        // 直接使用我们学习过的 IO 进行内容输出
        if (file.exists()) {
            // 返回静态内容
            return;
       }
        
        // 走到这里的逻辑都是动态内容了
        
        // 根据我们在配置中说的,按照 URL -> servlet-name -> Servlet 对象的链条
        // 最终找到要处理本次请求的 Servlet 对象
        Servlet ins = findInstance(req.getURL());
        
        // 调用 Servlet 对象的 service 方法
        // 这里就会最终调用到我们自己写的 HttpServlet 的子类里的方法了
        try {
       ins.service(req, resp); 
       } catch (Exception e) {
            // 返回 500 页面,表示服务器内部错误
       }
   }
}
  • Tomcat Socket 中读到的 HTTP 请求是一个字符串, 然后会按照 HTTP 协议的格式解析成一个HttpServletRequest 对象.
  • Tomcat 会根据 URL 中的 path 判定这个请求是请求一个静态资源还是动态资源. 如果是静态资源, 直接找到对应的文件把文件的内容通过 Socket 返回. 如果是动态资源, 才会执行到 Servlet 的相关 逻辑.
  • Tomcat 会根据 URL 中的 Context Path Servlet Path 确定要调用哪个 Servlet 实例的 service 方法.
  • 通过 service 方法, 就会进一步调用到我们之前写的 doGet 或者 doPost。

3、Servlet service 方法的实现 

class Servlet {
    public void service(HttpServletRequest req, HttpServletResponse resp) {
        String method = req.getMethod();
        if (method.equals("GET")) {
            doGet(req, resp);
       } else if (method.equals("POST")) {
            doPost(req, resp);
       } else if (method.equals("PUT")) {
            doPut(req, resp);
       } else if (method.equals("DELETE")) {
            doDelete(req, resp);
       } 
       ......
   }
}

根据Servlet对象来调用service方法,在service方法的内部又会进一步地调用doGet等方法。

通过上述整套流程中,可以看出Servlet的生命周期主要有三个阶段:

init:初始化阶段,对象创建好之后就会执行init方法,用户可以重写这个方法来初始化逻辑。

service:在处理请求阶段来调用,每次请求都会调用service。

destroy:退出主循环,tomcat结束之前都会调用来释放资源。 

六、Servlet关键API 

当前主要使用HttpServlet类、HttpServletRequest类和HttpServletResponse类。

1、HttpServlet类 

在写代码创建的类都继承自HttpServlet类,这个类有以下常用方法:

创建一个MethodServlet类继承Servlet类,并且重写doPost方法。

@WebServlet("/method")
public class MethodServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html;charset=utf8");//将字符集指定为utf-8,避免乱码
        resp.getWriter().write("POST响应");
    }
}

但是对于POST请求在浏览器中通过URL无法直接访问,就还需要通过form表单或者ajax来进行实现。

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
<script src="https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js"></script>
<script>
    $.ajax({
        type: 'post',
        url: 'method',
        success: function(body){
            console.log(body);
        }
    });
</script>
</body>
</html>

这个html在目录文件的位置:

通过127.0.0.1:8080/test/test.html在浏览器访问,通过控制台可以看到如下结果:

2、HttpServletRequest 类

HttpServletRequest类对应的是一个Http请求,当 Tomcat 通过 Socket API 读取 HTTP 请求, 并且按照 HTTP 协议的格式把字符串解析成 HttpServletRequest 对象。其常用方法:

上述的方法都只是进行读操作。 

打印HTTP请求信息

@WebServlet("/show")
public class ShowRequestServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html;charset=utf-8");
        StringBuilder respondBody = new StringBuilder();
        respondBody.append(req.getProtocol());
        respondBody.append("<br>");
        respondBody.append(req.getMethod());
        respondBody.append("<br>");
        respondBody.append(req.getRequestURI());
        respondBody.append("<br>");
        respondBody.append(req.getContextPath());
        respondBody.append("<br>");
        respondBody.append(req.getQueryString());
        respondBody.append("<br>");
        Enumeration<String> headerNames = req.getHeaderNames();
        while(headerNames.hasMoreElements()){
            String headerName = headerNames.nextElement();
            respondBody.append(headerName+" ");
            respondBody.append(req.getHeaders(headerName));
            respondBody.append("<br>");
        }
        resp.getWriter().write(respondBody.toString());
    }
}

 在浏览器通过url访问:

获取POST请求的参数 :

首先POST请求body的格式有:x-www-form-urlencoded,这种格式需要利用form表单来进行构造。

@WebServlet("/postParameter")
public class PostGetParameterServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String userName = req.getParameter("userName");
        String pwd = req.getParameter("pwd");
        resp.getWriter().write("userName:"+userName+" pwd:"+pwd);
    }
}
<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
    <form action="postParameter" method="post">
        <input type="text" name="userName">
        <input type="password" name="pwd">
        <input type="submit" value="提交">
    </form>
    <script src="https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js"></script>
</body>
</html>

运行效果:

  

点击提交按钮之后: 

POST请求body格式还有json格式,但是这种格式需要引入第三方库Jackson,需要在maven中心库中找到然后引入到pom.xml之中,然后前端代码中需要在JS构造出body格式为json的请求。 

<body>
    <input type="text" id="userName">
    <input type="text" id="password">
    <input type="button" value="提交" id="submit">
    
    <script src="https://cdn.staticfile.org/jquery/1.10.2/jquery.min.js"> </script>
    <script>
        let userNameInput = document.querySelector('#userName');
        let passwordInput = document.querySelector('#password');
        let button = document.querySelector('#submit');
        button.onclick = function(){
            $.ajax({
                type:'post',
                url:'postJason',
                contentType:'application/json',
                data:JSON.stringify({
                    userName:userNameInput.value,
                    password:passwordInput.value
                }),
                success:function(body){
                    console.log(body);
                }
            });
            }
    </script>
</body>

 后端代码使用Jackson,将请求从body中读取出来,并且解析为Java对象。

class User{
    public String userName;
    public String password;
}
@WebServlet("/postJason")
public class PostJasonServlet extends HttpServlet {
    //创建一个Jason对象
    private ObjectMapper objectMapper = new ObjectMapper();
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html;charset=utf8");
        User user = objectMapper.readValue(req.getInputStream(),User.class);
        resp.getWriter().write("userName:"+user.userName+" password:"+user.password);
    }
}

 运行效果:

提交之后可以在控制台上看到:

3、HttpServletResponse类

Servlet 中的 doXXX 方法的目的就是根据请求计算得到相应, 然后把响应的数据设置到 HttpServletResponse 对象中. 然后 Tomcat 就会把这个 HttpServletResponse 对象按照 HTTP 协议的格式, 转成一个字符串, 并通过 Socket 写回给浏览器.

其常见方法如下:

可以写一个自动刷新的页面: 

@WebServlet("/refresh")
public class RefreshServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setHeader("Refresh","1");
        resp.getWriter().write("time"+System.currentTimeMillis());
    }
}

 运行效果:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/335589.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C语言学习_DAY_2_变量的定义_输入与输出

高质量博主&#xff0c;点个关注不迷路&#x1f338;&#x1f338;&#x1f338;&#xff01; 目录 I. 变量的定义 II. 变量的赋值 III. 输出 IV. 输入 I. 变量的定义 首先&#xff0c;我们新建一个.c文件在Dev C中&#xff0c;并把之前定义好的程序框架放进去。 此时我…

丝绸之路——NFT 系列来袭!

丝绸之路的经历讲述了汉朝时代的一个重要历史事件。该系列中的 NFT 带有中国这段黄金时代令人愉悦的视觉元素&#xff0c;使其成为值得收藏的物品。 NFT 系列介绍 敦煌女神像01&#xff08;左&#xff09;&#xff1b;汉代士兵&#xff08;中&#xff09;&#xff1b;敦煌女神像…

Matlab与ROS(1/2)链接与入门(一)

0. 简介 Matlab作为广大学生以及算法工程师常用的软件&#xff0c;因其良好的可视化以及矩阵适应能力&#xff0c;使其得到了广泛的使用。同时ROS作为机器人、自动驾驶领域最常用的软件&#xff0c;其与Matlab结合在一起也是理所当然的。为此这一系列就是来带领读者熟悉并了解…

说说连接查询有哪些以及它们之间的区别?

一、左连接 -- 左连接 select t1.a,t2.b from (select 1 a from DUAL union ALL select 1 a from DUAL union ALL select 2 a from DUAL union ALL select 2 a from DUAL union ALL select 3 a from DUAL)t1 LEFT JOIN (select 1 b from DUAL union ALL select 2 b from DUAL …

【成为架构师课程系列】大数据技术体系精华总结【值得收藏!】

目录 大数据技术总结 #大纲 #概念 #应用 #难题 #技术栈 #大数据架构 #1. 数据收集

git报错大全,你将要踩的坑我都帮你踩了系列

使用git push -u origin master报下面的错&#xff1a; 使用git push -u origin master报下面的错&#xff1a; Updates were rejected because the remote contains work that you do not have locally&#xff0c;This is usually caused by another repository pushing to …

kubernetes基础

文章目录1.k8s1.概念2.特性3.核心组件1.k8s 1.概念 用于自动部署、扩展和管理“容器化&#xff08;containerized&#xff09;应用程序”的开源系统。 可以理解成 K8S 是负责自动化运维管理多个容器化程序&#xff08;比如 Docker&#xff09;的集群&#xff0c;是一个生态极…

【刷题笔记】--验证二叉搜索树--min,max参与递归

题目&#xff1a; 给你一个二叉树的根节点 root &#xff0c;判断其是否是一个有效的二叉搜索树。 有效 二叉搜索树定义如下&#xff1a; 节点的左子树只包含 小于 当前节点的数。 节点的右子树只包含 大于 当前节点的数。 所有左子树和右子树自身必须也是二叉搜索树。 示例…

【大唐杯备考】——5G基站开通与调测(学习笔记)

&#x1f4d6; 前言&#xff1a;本期介绍5G基站开通与调测。 目录&#x1f552; 1. 概述&#x1f552; 2. 5G基站开通与调测基础&#x1f558; 2.1 3.5GHz单模100MHz配置&#xff08;S111&#xff09;&#x1f558; 2.2 3.5GHz单模100MHz配置&#xff08;S111111&#xff09;&a…

车载以太网 - SomeIP - 杂项 - 09

SomeIP-SD Find Service Timing - 服务发现相关时间参数参数描述最小值标准值最大值T_Initial初始化时间0msNA1000msTTL生存时间NA5000msNAT_Cycle_Offer_Msg提供服务报文周期950ms1000ms1050msRepetition_Max最大重复次数NA3次NAInitial_dealy_Min初始化最小延迟NA90msNAIniti…

Spring、SpringMVC、Shiro、Maven

一、SpringSpring是一个为了解决企业应用程序开发复杂性而创建的开源框架&#xff0c;其核心是IOC–控制反转、AOP–面向切面编程。框架的主要优势之一就是其分层架构&#xff08;WEB层&#xff08;springMvc&#xff09;、业务层&#xff08;Ioc&#xff09;、持久层&#xff…

面向对象的基本概念和方法

面向对象的开发方法在近几十年见得以广泛应用&#xff0c;我们常见的Java语言就是一种典型的面向对象的开发语言。然而&#xff0c;面向对象的概念较为复杂&#xff0c;知识点也很细碎&#xff0c;本文整理了面向对象的基本概念和方法&#xff0c;供大家参考。为了便于读者理解…

Java笔记-多线程高阶

目录一、多线程1.为什么使用多线程&#xff1a;2.多线程使用场景&#xff1a;3.使用多线程要考虑的因素&#xff1a;二、线程间竞争对象锁的过程三、synchronized关键字1.synchronized的作用&#xff1a;2.synchronized执行效率&#xff1a;3.synchronized实现原理&#xff1a;…

P14 PyTorch AutoGrad

前言&#xff1a;激活函数与loss的梯度PyTorch 提供了Auto Grad 功能&#xff0c;这里系统讲解一下torch.autograd.grad系统的工作原理&#xff0c;了解graph 结构目录&#xff1a;1: require_grad False2: require_grad True3&#xff1a; 多层bakcward 原理4&#xff1a; in…

YOLO-V4经典物体检测算法介绍

在前文我们介绍了YOLO-V1~V3版本都做了哪些事&#xff0c;本文我们继续介绍YOLO-V4版本。YOLO的作者在发表完V3之后&#xff0c;发现YOLO产品被美国军方应用到了很多军事战争当中&#xff0c;这是他所不希望看见的&#xff0c;因此宣布不再继续研究。但历史和科技总是随时间不断…

(第五章)OpenGL超级宝典学习:统一变量(uniform variable)

统一变量 前言 本篇在讲什么 本篇记录对glsl中的变量uniform的认知和学习 本篇适合什么 适合初学Open的小白 适合想要学习OpenGL中uniform的人 本篇需要什么 对C语法有简单认知 对OpenGL有简单认知 最好是有OpenGL超级宝典蓝宝书 依赖Visual Studio编辑器 本篇的特色 …

设计模式-组合模式和建筑者模式详解

一. 组合模式1. 背景在现实生活中&#xff0c;存在很多“部分-整体”的关系&#xff0c;例如&#xff0c;大学中的部门与学院、总公司中的部门与分公司、学习用品中的书与书包、生活用品中的衣月艮与衣柜以及厨房中的锅碗瓢盆等。在软件开发中也是这样&#xff0c;例如&#xf…

spring注解的开端(@Component替代bean标签的使用)

目录 一、介绍 1.什么是注解开发&#xff1f; 2.Spring注解的版本 3.基于spring注解的应用 4. Component的细分注解 5.相关注解 二、简单例子讲解 1.类打注解 2.扫描注解放入工厂 3.总工厂取注解调用 4.运行结果 总结&#xff1a; 一、介绍 1.什么是注解开发&…

人工智能聊天工具ChatGPT为Delphi写的诗歌

现在每个人似乎都在谈论 ChatGPT&#xff0c;所以这里有一首关于我们最喜欢的开发工具Delphi的好诗&#xff0c;来自 ChatGPT 生成的 Embarcadero 的 Delphi。 Delphi&#xff0c;哦&#xff0c;Delphi&#xff01; 作者&#xff1a;ChatGPT Delphi&#xff0c;哦&#xff0c;…

java面试题(十九) Mybatis

4.1 谈谈MyBatis和JPA的区别 参考答案 ORM映射不同&#xff1a; MyBatis是半自动的ORM框架&#xff0c;提供数据库与结果集的映射&#xff1b; JPA&#xff08;默认采用Hibernate实现&#xff09;是全自动的ORM框架&#xff0c;提供对象与数据库的映射。 可移植性不同&…