Java Web(八)--Servlet(一)

news2024/10/2 22:28:54

介绍

官网:Servlet 3.1 API Documentation - Apache Tomcat 8.0.53

为什么需要?

提出需求: 请用你现有的html css javascript,开发网站,比如可以让用户留言/购物/支付?

引入我们动态网页(能和用户交互)技术===>Servlet

是什么?

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

   Servlet通常通过 HTTP(超文本传输协议)接收和响应来自 Web 客户端的请求。从原理上来讲,Servlet可以响应任何类型的请求,但绝大多数情况下Servlet只用来扩展基于HTTP协议的Web服务器

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

Servlet技术的核心是Servlet,它是所有Servlet类必须直接或者间接实现的一个接口。在编写实现Servlet接口的类时,直接实现它,在扩展实现Servlet这个接口的类时,间接实现它。Servlet有三种实现方式:实现Servlet接口、继承抽象类GenericServlet、继承HttpServlet。

【Tomcat部分详见Java Web(七)__Tomcat(二)-CSDN博客和Java Web(七)__Tomcat(一)-CSDN博客 】

注:

 Servlet 类没有 main() 函数,不能独立运行,只能作为一个模块被载入到 Servlet 容器,然后由 Servlet 容器来实例化,并调用其中的方法;

一个动态页面对应一个 Servlet 类,开发一个动态页面就是编写一个 Servlet 类;【当用户请求到达时,Servlet 容器会根据配置文件(web.xml)来决定调用哪个类】 

浏览器访问 Servlet 流程分析 

注:

servlet3.0 前使用 web.xml 
servlet3.0 版本以后(包括 3.0)支持注解, 同时支持 web.xml。


Servlet的开发

实现Servlet接口__麻烦

需求:
1、开发一个 HelloServlet
2、当浏览器 访问 http://localhost:8080/web 应用名/helloServlet 时,后台输出 "hiHelloServelt"

实现:

1、编写类HelloServlet,实现  Servlet 接口

  •     1.创建javaweb工程,并配置好Tomcat
  •     2.添加servlet.jar(在Tomcat/lib)到工程web/WEB-INF/lib中
  •     3.在src 下 包 com.hspedu.servlet.HelloServlet.java ,并实现Servlet接口

2、实现  service 方法,处理请求,并响应数据

package com.lhyedu.servlet;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

/**
 * 1. 开发一个Servlet 需要 实现Servlet接口
 * 2. 实现Servlet接口的方法5个
 */
public class HelloServlet02 implements Servlet {

    /**
     * 1.初始化 servlet
     * 2.当创建HelloServlet 实例时,会调用init方法
     * 3. 该方法只会被调用一次
     */
    @Override
    public void init(ServletConfig servletConfig) throws ServletException {
    }

    /**
     * 返回ServletConfig 也就是返回Servlet的配置
     */
    @Override
    public ServletConfig getServletConfig() {
        return null;
    }

    /**
     * 1. service方法处理浏览器的请求(包括get/post)
     * 2. 当浏览器每次请求Servlet时,就会调用一次service
     * 3. 当tomcat调用该方法时,会把http请求的数据封装成实现ServletRequest接口的request对象
     * 4. 通过servletRequest 对象,可以得到用户提交的数据
     * 5. servletResponse 对象可以用于返回数据给tomcat->浏览器
     */
    @Override
    public void service(ServletRequest servletRequest,
                        ServletResponse servletResponse) throws ServletException, IOException {
        HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
        String method = httpServletRequest.getMethod();
        if("GET".equals(method)) {
            doGet(); //用doGet() 处理GET请求
        } else if("POST".equals(method)) {
            doPost(); //用doPost() 处理POST请求
        }
    }

    /**
     * 用于响应get请求的
     */
    public void doGet() {
        System.out.println("doGet() 被调用..");
    }

    /**
     * 用于响应post请求的
     */
    public void doPost() {
        System.out.println("doPost() 被调用..");
    }

    /**
     * 返回servlet信息,使用较少
     */
    @Override
    public String getServletInfo() {
        return null;
    }

    /**
     * 1. 该方法是在servlet销毁时,被调用
     * 2. 只会调用一次
     */
    @Override
    public void destroy() {
        System.out.println("destroy() 被调用...");
    }
}

3、在  web.xml  中去配置  servlet 程序的访问地址,即:给hello.servlet提供对外访问的地址。  

<?xml version="1.0" encoding="UTF-8"?>
<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_4_0.xsd"
         version="4.0">

    <!--web.xml主要用来配置该web应用使用到的Servlet-->
    <!-- 配置HelloServlet -->
    <!--servlet标签: 给tomcat配置Servlet程序-->

    <servlet>
        <!--servlet-name标签: 给Servlet程序取一个别名(程序员决定), 该名字唯一;一般跟写的Servlet类名相同-->
        <!--servlet-class标签:Servlet的全限定类名,即Servlet类的位置: Tomcat在反射生成该Servlet需要使用。-->
        <servlet-name>HelloServlet</servlet-name>
        <servlet-class>HelloServlet</servlet-class>

        <!--load-on-startup 表示在tomcat 启动时,会自动的加载servlet实例-->
        <!--<load-on-startup>1</load-on-startup>-->
    </servlet>

    <!--servlet-mapping标签: 给Servlet程序配置方位地址-->

    <servlet-mapping>
        <!--servlet-name标签:告诉服务器,当前配置的地址给哪个Servlet使用-->
        <!--url-pattern标签:对外提供访问Servlet的url地址:http://ip[域名]:port/工程路径/helloServlet
            取名是程序员决定的,相当于项目名。【/符号一定要加上】-->

        <servlet-name>HelloServlet</servlet-name>
        <url-pattern>/helloServlet</url-pattern>

    </servlet-mapping>

执行步骤:

【1】首先浏览器通过http://localhost:8080/servletDemo/helloServlet来找到web.xml中的url-pattern;

【2】匹配到url-pattern后,就会找到servlet的名字helloServlet;

【3】通过servlet-name找到servlet-class【即servlet的位置】,然后到其中找到对应的处理方式进行处理。

 <load-on-startup>标签:

  • <load-on-startup>节点必须写在<servlet>节点的内部,且作为最后一个节点,取值必须是整数;
  • 如果是大于等于0的整数:表示在服务器启动时就被创建并初始化。【避免第一次访问时被创建并初始化的,减少第一次访问的耗时】
  • 如果有多个Servlet设置了<load-on-startup>节点的值,那么值越小越优先执行;
  • 如果是负数则表示第一次被访问时创建并初始化,也就是默认情况,可以省略不写。

 4、通过浏览器访问HelloServlet ,进行验证;

  • 浏览器输入:http://localhost:8080/web/HelloServlet
  • 服务后台输出:  hi,helloservlet......  

实现GenericServlet

GenericServlet做了如下工作:
• 提升init方法中原本是形参的servletConfig对象的作用域(成员变量 , 方便其他方法使用)
• init方法中还调用了一个init空参方法, 如果我们希望在servlet创建时做一些什么初始化操作,可以继承GenericServlet后,覆盖init空参方法
• 由于其他方法内也可以使用servletConfig, 于是写了一个getServletContext方法
• 但没有实现service()方法


实现HttpServlet类__推荐方式

示意图:

package com.hspedu.servlet;

import javax.servlet.*;
import javax.servlet.http.*;
import java.io.IOException;

public class OKServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//可以写自己的业务处理代码
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//可以写自己的业务处理代码
    }
}

【1】热加载选项说明

on update action

  •     表示当我们更新操作时, Tomcat 会自动更新类和资源 
  •    当jsp/html 文件修改时,可以生效;但是如果你修改的 java 文件,需要 Redepoly 才会生效。

on frame deactivation

  •     表示 IDEA 失去焦点(比如最小化),也会导致  jsp/html 发生更新
  •    但是 java 修改了,还是需要 redeploy

【2】端口修改

只会影响到当前的项目,而不是去修改 server.xml。


DOS部署

在默认情况下,Tomcat 会自动加载 webapps 目录下的 JavaWeb 应用,并把它发布到名为 localhost 的虚拟主机中。

部署 JavaWeb 应用最快捷的方式:直接将 JavaWeb 应用的所有文件复制到 Tomcat 的 /webapps 目录下

运行方式:

  1.     开放式目录结构(只编译不打包);在开发阶段采用,方便调试
  2.     打包文件(WAR 文件):产品发布阶段时,应该将整个应用打包成 WAR 文件,再进行部署。Tomcat 启动时也会将 WAR 文件自动展开为开放式的目录结构。

 开放式目录结构__部署步骤

1. 进入 Windows DOS 命令行窗口

  •     使用快捷键 “Windows + R”,打开运行对话框
  •     在对话框输入cmd,点击“确定”,进入 Windows 系统命令行窗口

2. 引入 javax.servlet 包

先在命令行中输入set classpath=,然后将 servlet-api.jar 文件拖进命令行内,回车执行 。

  •     命令:set classpath = path
    •         path 表示引入 jar 包的路径
    •         set classpath命令用来为当前窗口设置临时环境变量,只在当前窗口下有效。

3. 编译 Servlet

  •     1)在命令提示符中使用 cd命令进入 MyServlet.java 所在的目录
  •     2)使用 javac -encoding UTF-8 -d . MyServlet.java 命令进行编译
  •     3)进入 MyServlet.java 文件所在的目录,可发现新增了编译后的目录和 .classes 字节码文件,即完成对 Servlet 的编译工作

4. 创建目录结构

    依照 JavaWeb 应用的固定目录结构,在 Tomcat 中为该 Servlet 创建目录。

  •     目录
    •         在 Tomcat 的 webapps 目录中创建 servletDemo(web 应用的名字,由自己定义)文件夹;
    •         在 servletDemo 文件夹内创建 WEB-INF 文件夹;
    •         在 WEB-INF 内创建 classes 文件夹;
    •         在 WEB-INF 内创建配置文件 web.xml(可以复制 \webapps\ROOT\WEB-INF 中的 web.xml 使用)

5. 将 Servlet 移动到 Tomcat 目录中

  •     编译好的字节码和目录移动到 Tomcat\webapps\servletDemo\WEB-INF\classes 目录下

6. 配置 web.xml

  •     对 webapps\servletDemo\WEB-INF 目录的 web.xml 中进行配置

7、访问

  •     进入 Tomcat\bin 目录下双击 startup.bat,启动 Tomcat。
  •     浏览器的地址栏中输入“http://localhost:8080/servletDemo/MyServlet”,访问 MyServlet

Servlet的生命周期

 Servlet 的生命周期由 Servlet 容器管理;在 javax.servlet.Servlet 接口中定义3 个方法:init()、service()、destory(),它们分别在 Servlet 生命周期的不同阶段被 Servlet 容器调用。

【1】初始化阶段

Servlet 容器(比如: Tomcat)加载 Servlet,加载完成后,Servlet 容器会创建一个 Servlet 实例并调用init()方法,init()方法只会调用一次。

    (1)加载和实例化Servlet

        加载成功后,容器会通过反射对 Servlet 进行实例化【编写 Servlet 类时,需要一个无参构造方法】;

        Servlet 容器装载 Servlet的情形:

  •             当容器启动或首次请求某个 Servlet 时,容器会读取 web.xml 或 @WebServlet 中的配置信息,对指定的 Servlet 进行加载;
  •             Servlet 重新装载时,浏览器再向 Servlet 发送请求的第 1 次;比如 tomcat 进行 redeploy;【redeploy 会销毁所有的Servlet 实例】。
通过在 web.xml 文件中添加<load-on-startup>1</load-on-startup>
 1 表示装载的顺序,默认值为0;

load-on-startup 是 web.xml 中的一个节点,是 servlet 元素的子元素,用来标记 Servlet 容器启动时是否初始化当前 Servlet,以及当前 Servlet 的初始化顺序

    (2)调用init()方法初始化Servlet实例

        在 Servlet 的整个生命周期内,init() 方法只能被调用一次。

        初始化期间,Servlet 实例可以通过 ServletConfig 对象获取在 web.xml 或者 @WebServlet 中配置的初始化参数。

【2】处理浏览器请求阶段(service 方法)

当初始化完成后,Servlet 容器会将该实例保存在内存中,通过调用它的 service() 方法,为接收到的请求服务。    

每收到一个 http 请求,服务器就会产生一个新的线程去处理;对于 Servlet 的每一次请求,Servlet 容器都会调用一次 service() 方法,并创建新的 ServletRequest 和 ServletResponse 对象;即 service() 方法在 Servlet 的整个生命周期中会被调用多次。

    Servlet 容器接收到来自客户端请求时,容器会针对该请求分别创建一个 ServletRequst 对象和 ServletResponse 对象,将它们以参数的形式传入 service() 方法内,并调用该方法对请求进行处理;

  •          ServletRequst 对象获取客户端的相关信息和请求信息;
  •         ServletResponse 对象将响应信息进行包装,返回给客户端;
  •         当 Servlet 容器将响应信息返回给客户端后,ServletRequst 对象与 ServletResponse 对象就会被销毁。
    @Override
    public void service(ServletRequest servletRequest, ServletResponse servletResponse) throws ServletException, IOException {
        //count值,在不断的累计,说明HelloServlet是单例的
         count++;
       //tomcat每处理一次http请求,就生成一个新的线程
        System.out.println("hi,helloservlet......" + count + Thread.currentThread().getId());
    }

   注:执行 service() 方法前,init() 方法必须已成功执行;

【3】终止阶段 destory 方法(体现 Servlet 完整的生命周期)

    当web 应用被终止,或者Servlet 容器终止运行,或者Servlet 类重新装载时,会调用destroy()方法,释放该实例使用的资源;

比如重启tomcat ,或者  redeploy web 应用;例如:关闭数据库连接,关闭文件的输入流和输出流等,随后该实例被 Java 的垃圾收集器所回收。

    对于每个 Servlet 实例来说,destory() 方法只能被调用一次;

    注:要看到 destory 效果,需要保证 servlet 实例被创建过或者 Servlet 重新装载时(比如 redeploy)。


其他

部署动态网站

一般至少需要三个组件,分别是 Web 服务器、脚本语言运行时和数据库。例如,部署 PHP 网站一般选择「Apache + PHP 运行时 + MySQL」的组合。

【1】web服务器 

一种对外提供 Web 服务的软件,可以接收浏览器的 HTTP 请求,并将处理结果返回给浏览器。

  •             运行 PHP 网站一般选择 Apache 或者 Nginx;
  •             运行 ASP/ASP.NET 网站一般选择 IIS;
  •             运行 Python 网站一般选择内置的 WSGI 服务器模块——wsgiref

    通常所说的 Web 服务器,功能往往都比较单一,一般只能提供 http(s) 服务,让用户访问静态资源(HTML 文档、图片、CSS 文件、JavaScript 文件等)。它们不能执行任何编程语言,也不能访问数据库,更不能让用户注册和登录。

   若只有 Web 服务器,那您只能部署静态网站,不能部署动态网站。

【2】运行环境(运行时)

    习惯将以上各种支持脚本语言运行的部件统称为运行环境,或者运行时(Runtime)。开发网站使用的编程语言一般都是脚本语言(比如 PHP、ASP、Python)。

    部署网站时都是将源代码直接扔到服务器上,然而源代码自己并不能运行,必须要有解释器的支持。当用户访问动态页面时,解释器负责分析、编译和执行源代码,然后得到处理结果。

    解释器:执行脚本语言的核心部件。包含如下辅助性的部件:

  •             垃圾回收器:负责及时释放不需要的内存,腾出资源供其它页面使用
  •             标准库:任何编程语言都会附带标准库;它们提供了很多通用性的功能,极大地提高了开发效率,避免重复造轮子

【3】数据库

    Web 服务器不带数据库,编程语言也不带数据库。数据库是一款独立的软件,若要实现用户注册、发布文章、提交评论等功能,就必须安装一款数据库。

  •         比如 MySQL、Oracle、SQL Server 等。

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

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

相关文章

医院LIS(全称Laboratory Information Management System)系统源码

目录 一、医院LIS系统概况 二、医院LIS系统建设必要性 三、为什么要使用LIS系统 四、技术框架 &#xff08;1&#xff09;总体框架 &#xff08;2&#xff09;技术细节 &#xff08;3&#xff09;LIS主要功能模块 五、LIS系统优势 &#xff08;1&#xff09;客户/用户…

【Python】记录生产编程小tips(字符串处理、列表删除、字典、csv、excel操作)持续更新

文章目录 一.for循环删除列表元素1.删除list元素方法2.直接删除往往结果与期望不一致3.循环删除元素的正确方法&#xff1a;方法1&#xff1a;while循环i减方法2&#xff1a;使用copy方法3&#xff1a;倒叙遍历 二.字符串处理库三.字典—dict运用四.csv操作五.excel操作1.读exc…

AI:139-基于深度学习的语音指令识别与执行

🚀点击这里跳转到本专栏,可查阅专栏顶置最新的指南宝典~ 🎉🎊🎉 你的技术旅程将在这里启航! 从基础到实践,深入学习。无论你是初学者还是经验丰富的老手,对于本专栏案例和项目实践都有参考学习意义。 ✨✨✨ 每一个案例都附带关键代码,详细讲解供大家学习,希望…

改进 RAG:自查询检索

原文地址&#xff1a;Improving RAG: Self Querying Retrieval 2024 年 2 月 11 日 让我们来解决构建 RAG 系统时的一个大问题。 我们不能依赖语义搜索来完成每个检索任务。只有当我们追求单词的含义和意图时&#xff0c;语义搜索才有意义。 But in case&#xff0c;我们正…

python自动化管理和zabbix监控网络设备(有线网络和路由配置部分)

目录 目录 一、拓扑图 二、core-sw1 三、core-sw2 四、sum-sw1 五、sum-sw2 六、FW1 七、DMZ-SW1 结语 一、拓扑图 二、core-sw1 sys sysname core-sw1 vlan batch 10 20 30 40 50 60 100 vlan batch 200 210 220 230 240 250 stp region-configuration region-name…

选择稳定代理IP需要考虑哪些因素?

很多人不知道怎么选择稳定的代理IP&#xff0c;也不知道当前代理IP套餐是否稳定&#xff0c;今天我们一起来分析下&#xff0c;选择稳定的代理IP可以从哪几方面去考虑。 1、代理IP的可用性 代理IP要稳定&#xff0c;先要可以用。一个代理IP池是否稳定&#xff0c;要看代理IP的…

区分服务 DiffServ

目录 区分服务 DiffServ 区分服务的基本概念 区分服务 DiffServ 的要点 每跳行为 PHB DiffServ 定义的两种 PHB 区分服务 DiffServ 区分服务的基本概念 由于综合服务 IntServ 和资源预留协议 RSVP 都较复杂&#xff0c;很难在大规模的网络中实现&#xff0c;因此 IET…

Docker复习笔记

Centos7安装Docker Docker官网:www.docker.com Docker官网仓库:hub.docker.com Docker文档是比较详细的 安装相关依赖 yum -y install gcc gcc-c yum install -y yum-utils 设置docker镜像仓库 yum-config-manager --add-repo https://download.docker.com/linux/centos/do…

Mysql运维篇(五) 部署MHA--主机环境配置

一路走来&#xff0c;所有遇到的人&#xff0c;帮助过我的、伤害过我的都是朋友&#xff0c;没有一个是敌人。如有侵权&#xff0c;请留言&#xff0c;我及时删除&#xff01; 大佬博文 https://www.cnblogs.com/gomysql/p/3675429.html MySQL 高可用&#xff08;MHA&#x…

js:通过input标签或Drag拖拽文件实现浏览器文件上传获取File文件对象

文档 https://developer.mozilla.org/zh-CN/docs/Web/API/Filehttps://developer.mozilla.org/zh-CN/docs/Web/API/HTMLElement/drag_event 通过读取文件可以获取File对象的信息 lastModified: 1707210706000 lastModifiedDate: Tue Feb 06 2024 17:11:46 GMT0800 (中国标准…

使用 Verilog 做一个可编程数字延迟定时器 LS7211-7212

今天的项目是在 Verilog HDL 中实现可编程数字延迟定时器。完整呈现了延迟定时器的 Verilog 代码。 所实现的数字延迟定时器是 CMOS IC LS7212&#xff0c;用于生成可编程延迟。延迟定时器的规格可以在这里轻松找到。基本上&#xff0c;延迟定时器有 4 种操作模式&#xff1a;…

备考北京高考数学:历年选择题真题练一练和解析(2014-2023)

还有三个多月的时间就要高考了&#xff0c;我们今天继续看北京市高考数学真题和解析。今天看5道选择题。独家制作的在线练习集&#xff0c;可以便捷地反复刷这些真题&#xff0c;吃透真题&#xff08;背后的知识点和解题技巧&#xff09;&#xff0c;让高考数学再上一个台阶。 …

【LeetCode:2476. 二叉搜索树最近节点查询 + 中序遍历 + 有序表】

&#x1f680; 算法题 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;…

【算法小讲堂】#1 贪心算法

引入——关于贪心算法 我们先来做一个小游戏——现在假设自己是一个小偷&#xff0c;桌上有一些物品&#xff0c;包括一台iPhone15、一个充电宝、一个眼罩和一个溜溜梅。此时&#xff0c;你听说警察即将到来&#xff0c;那么你会先带走哪个东西呢&#xff1f; 一般来讲&#xf…

[云原生] 二进制安装K8S(上)搭建单机matser、etcd集群和node节点

一、单机matser预部署设计 目前Kubernetes最新版本是v1.25&#xff0c;但大部分公司一般不会使用最新版本。 目前公司使用比较多的&#xff1a;老版本是v1.15&#xff0c;因为v1.16改变了很多API接口版本&#xff0c;国内目前使用比较多的是v1.18、v1.20。 组件部署&#xff…

beego代理前端web的bug

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 一、beego代理前端web的bug总结 一、beego代理前端web的bug *报错&#xff0c;为web压缩包index.html里面的注释被错误解析&#xff0c;删掉就行 2024/02/22 10:2…

[HarekazeCTF2019]encode_and_encode 不会编程的崽

这题知道这个知识点就挺好做的 <?php error_reporting(0);if (isset($_GET[source])) {show_source(__FILE__);exit(); }function is_valid($str) {$banword [// no path traversal\.\.,// no stream wrapper(php|file|glob|data|tp|zip|zlib|phar):,// no data exfiltra…

如何实现固定公网地址远程访问内网Wagtail管理界面

文章目录 前言1. 安装并运行Wagtail1.1 创建并激活虚拟环境 2. 安装cpolar内网穿透工具3. 实现Wagtail公网访问4. 固定的Wagtail公网地址 前言 Wagtail是一个用Python编写的开源CMS&#xff0c;建立在Django Web框架上。Wagtail 是一个基于 Django 的开源内容管理系统&#xf…

【精品】OnlyOffice 8.0 版本深度测评

引言 官网链接&#xff1a; ONLYOFFICE 官方网址 OnlyOffice 是一套全面的开源办公协作软件&#xff0c;旨在为用户提供强大、便捷和安全的文档处理和协作环境。最新发布的 OnlyOffice 8.0 版本带来了一系列引人瞩目的新特性和功能改进&#xff0c;进一步提升了其在功能丰富性…

Pyglet综合应用|推箱子游戏之关卡图片载入内存

目录 读取图片 分割图片 综合应用 本篇为之前写的博客《怎样使用Pyglet库给推箱子游戏画关卡地图》的续篇&#xff0c;内容上有相关性&#xff0c;需要阅读的请见链接&#xff1a; https://hannyang.blog.csdn.net/article/details/136209138 「推箱子」是一款风靡全球的益…