Java中的Servlet你了解吗?

news2024/11/17 1:38:47

☆* o(≧▽≦)o *☆嗨~我是小奥🍹
📄📄📄个人博客:小奥的博客
📄📄📄CSDN:个人CSDN
📙📙📙Github:传送门
📅📅📅面经分享(牛客主页):传送门
🍹文章作者技术和水平有限,如果文中出现错误,希望大家多多指正!
📜 如果觉得内容还不错,欢迎点赞收藏关注哟! ❤️

文章目录

  • Servlet详解
    • 1. Servlet接口
      • (1) ServletConfig
      • (2) ServletContext
      • (3) 使用
    • 2.GenericServlet
    • 3. HttpServlet

Servlet详解

Servlet是Server + Applet的缩写,表示一个服务器应用。
其实,Servlet就是一套规范,我们按照这套规范写出来的代码就可以直接在Java服务器上运行。

Servlet3.1中的Servlet结构如下图所示:
在这里插入图片描述

1. Servlet接口

说到规范,那当然还是接口最重要了,我们看一下接口的定义:

package javax.servlet;

import java.io.IOException;

/**
 * 定义所有servlet必须实现的方法。
 * servlet是在Web服务器中运行的小Java程序。servlet通常通过HTTP(超文本传输协议)接收和响应来自Web客户机的请求。
 * 要实现这个接口,您可以编写一个扩展javax.servlet.GenericServlet的通用servlet,或者编写一个扩展javax.servlet.http.HttpServlet的HTTP servlet。
 * 该接口定义了初始化servlet、服务请求和从服务器中删除servlet的方法。这些被称为生命周期方法,按以下顺序调用:
 * 先构造servlet,然后用init方法进行初始化。
 * 从客户机到服务方法的任何调用都将被处理。
 * servlet退出服务,然后使用destroy方法销毁,然后进行垃圾收集并最终完成。
 * 除了生命周期方法之外,该接口还提供了getServletConfig方法和getServletInfo方法,
 * servlet可以使用该方法获取任何启动信息,getServletInfo方法允许servlet返回关于自身的基本信息,例如作者、版本和版权。
 */
public interface Servlet {

    /**
     * 由servlet容器调用,以指示servlet正在被放入服务中。
     * servlet容器在实例化servlet之后只调用init方法一次。init方法必须成功完成,servlet才能接收任何请求。
     * 如果使用init方法,servlet容器不能将servlet放入服务中:
     * 1.抛出ServletException
	 * 2.没有在Web服务器定义的时间段内返回
     */
    public void init(ServletConfig config) throws ServletException;
    
    /**
     *
     * 返回一个ServletConfig对象,其中包含此servlet的初始化和启动参数。
     * 返回的ServletConfig对象是传递给init方法的对象。
     * 这个接口的实现负责存储ServletConfig对象,以便这个方法可以返回它。实现这个接口的GenericServlet类已经做到了这一点。
     */
    public ServletConfig getServletConfig();
    
    /**
     * 由servlet容器调用,以允许servlet响应请求。
     * 此方法仅在servlet的init()方法成功完成后调用。
     * 响应的状态码应该始终为抛出或发送错误的servlet设置。
     * servlet通常运行在多线程servlet容器中,可以并发处理多个请求。
     * 开发人员必须注意同步访问任何共享资源,如文件、网络连接以及servlet的类和实例变量。
     */
    public void service(ServletRequest req, ServletResponse res) throws ServletException, IOException;
	
    /**
     * 返回有关servlet的信息,如作者、版本和版权。
     * 此方法返回的字符串应该是纯文本,而不是任何类型的标记(如HTML、XML等)。
     */
    public String getServletInfo();
    
    /**
     *
     * 由servlet容器调用,以指示servlet正在退出服务。
     * 此方法仅在servlet服务方法中的所有线程都退出或超时时间过后才调用。
     * 在servlet容器调用此方法之后,它将不会在此servlet上再次调用该服务方法。
     * 此方法为servlet提供了一个机会来清理任何被占用的资源(例如,内存、文件句柄、线程),
     * 并确保任何持久状态都与servlet在内存中的当前状态同步。
     */
    public void destroy();
}

简单介绍一下几个方法的作用:

  • init:init方法在容器启动时被容器调用(当load-on-startup设置位负数或者不设置时会在Servlet第一次用到时才会被调用),只会调用一次;
  • getServletConfig:用于获取ServletConfig,即Servlet的配置;
  • service:用于具体处理一个请求;
  • getServletInfo:获取一些Servlet相关的信息,如作者、版权等,默认返回空串;
  • destroy:用于在Servlet销毁时释放资源,也只会调用一次;

(1) ServletConfig

ServletConfig指的是Servlet的配置,也就是我们在web.xml中定义的Servlet时通过init-param标签配置的参数就是通过ServletConfig来保存的。

比如定义Spring MVCServlet时指定配置文件位置的contextConfigLocation参数就保存在ServletConfig中,如下:

<servlet>
	<servlet-name>demoDispatcher</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
    	<param-name>contextConfigLocation</param-name>
        <param-value>demo-servlet.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>

下面我们看一下ServletConfig接口的定义:

package javax.servlet;

import java.util.Enumeration;

/**
 * 一个servlet配置对象,由servlet容器使用,在初始化期间向servlet传递信息。
 */
 public interface ServletConfig {
    
    /**
     * 返回此servlet实例的名称。该名称可以通过服务器管理提供,在web应用程序部署描述符中分配,
     * 或者对于未注册(因此未命名)的servlet实例,它将是servlet的类名。
     */
    public String getServletName();

    /**
     * 返回对调用者正在其中执行的ServletContext的引用。
     */
    public ServletContext getServletContext();
    
    /**
     * 获取具有给定名称的初始化参数的值。
     */
    public String getInitParameter(String name);

    /**
     * 返回servlet初始化参数的名称,作为String对象的枚举,如果servlet没有初始化参数,则返回空枚举。
     */
    public Enumeration<String> getInitParameterNames();
}

简单介绍一下几个方法的作用:

  • getServletName:用于获取Servlet的名字,也就是我们在web.xml中定义的servlet-name
  • getServletContext:获取ServletContext,表示我们这个应用本身;
  • getInitParameter:获取init-param配置的参数;
  • getInitParameterNames:获取配置的所有init-param的名字集合;

(2) ServletContext

ServletContext非常重要,代表的其实就是我们应用本身。

那么自然,ServletContext中设置的参数可以被我们当前应用的所有Servlet共享,也就是我们在写功能时,把一些参数保存在Application中,其实就是保存在了ServletContext中了。

这里只是简单了解一下ServletContext

(3) 使用

ServletConfigServletContext最常见的使用之一是传递初始化参数

<!-- web.xml -->
<?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_3_1.xsd"
         version="3.1" metadata-complete="true">
    <display-name>initParam Demo</display-name>
    <context-param>
    	<param-name>contextConfigLocation</param-name>
        <param-value>application-context.xml</param-value>
    </context-param>
    <servlet>
    	<servlet-name>DemoServlet</servlet-name>
        <servlet-class>com.excelib.DemoServlet</servlet-class>
        <init-param>
        	<param-name>contextConfigLocation</param-name>
            <param-value>demo-servlet.xml</param-value>
        </init-param>
    </servlet>
    ...
</web-app>
  • 通过context-param配置的contextConfigLocation配置到了servletContext
  • servlet下面的init-param配置的contextConfigLocation配置到了ServletConfig

在Servlet中可以分别通过它们的getInitParameter方法进行获取,比如:

	String contextLocation = getServletConfig().getServletContext().getInitParameter("contextConfigLocation");
   String servletLocation = getServletConfig().getInitParameter("contextConfigLocation");

另外**ServletContext中非常常用的用法就是保存Application级别的属性**,比如:

	getServletContext().setAttribute("contextConfigLocation", "new path");

需要注意的是,这里设置的同名的Attribute并不会覆盖initParameter中的参数值,它们是两套数据,互不干扰。

ServletConfig不可以设置属性

2.GenericServlet

GenericServletServlet的默认实现,主要做了三件事情:

  • 实现了ServletConfig接口,我们可以直接调用该接口里面的方法;
  • 提供了无参的init方法;
  • 提供了log方法;

实现了ServletConfig接口

这样我们在需要调用ServletConfig中方法的时候可以直接调用,而不需要先获取ServletConfig了。其实是在底层帮我们内部调用了,源码如下:

    /**
     * 返回对servlet在其中运行的ServletContext的引用。
     * 提供这种方法是为了方便。它从servlet的ServletConfig对象获取上下文。
     */
    public ServletContext getServletContext() {
        ServletConfig sc = getServletConfig(); // 先获取ServletConfig
        if (sc == null) {
            throw new IllegalStateException(
                lStrings.getString("err.servlet_config_not_initialized"));
        }

        return sc.getServletContext();
    }

提供了无参的init方法

GenericServlet实现了Servlet的init(ServletConfig config)方法,在里面将config设置给了内部变量config,然后调用无参的init方法,该方法是一个模板方法,在子类中可以通过覆盖它来完成自己的初始化工作,如下:

    /**
     * 由servlet容器调用,以指示servlet正在被放入服务中。
     * 这个实现存储了它从servlet容器接收到的ServletConfig对象,以供以后使用。
     * 当重写这种形式的方法时,调用super.init(config)。
     */
    public void init(ServletConfig config) throws ServletException {
        this.config = config;
        this.init();
    }

    /**
     *一个方便的方法,可以被重写,这样就不需要调用super.init(config)。
     * 而不是重写init(ServletConfig),只需重写这个方法,它将被GenericServlet调用。
     * init (ServletConfig配置)。ServletConfig对象仍然可以通过getServletConfig来检索。
     */
    public void init() throws ServletException {

    }

这样做有三个好处:

  • 将参数config设置给内部属性config,这样就可以在ServletConfig的接口方法中直接调用config的相应方法来执行;
  • 之后写Servlet时只需要处理自己的初始逻辑,不需要再关注config
  • 重写init方法时也不需要再调用super.init(config)

提供了log方法

  • 记录日志的log
  • 记录异常的log

具体实现是通过传给ServletContext的日志实现的。

    /**
     * 将指定的消息写入servlet日志文件,并以servlet的名称作为前置。
     */     
    public void log(String msg) {
    getServletContext().log(getServletName() + ": "+ msg);
    }
   
   
    /**
     * 将给定Throwable异常的解释性消息和堆栈跟踪写入servlet日志文件,并以servlet名称为前缀。
     */   
    public void log(String message, Throwable t) {
    getServletContext().log(getServletName() + ": " + message, t);
    }

完整源码如下:

package javax.servlet;

import java.io.IOException;
import java.util.Enumeration;
import java.util.ResourceBundle;

/**
 * 定义一个通用的、独立于协议的servlet。要编写用于Web的HTTP servlet,请扩展javax.servlet.http.HttpServlet。
 * GenericServlet实现Servlet和ServletConfig接口。GenericServlet可以由servlet直接扩展,
 * 尽管更常见的是扩展特定于协议的子类,如HttpServlet。
 * GenericServlet使编写servlet更容易。它提供了生命周期方法init和destroy的简单版本,以及ServletConfig接口中的方法。
 * GenericServlet还实现了在ServletContext接口中声明的日志方法。
 * 要编写通用servlet,只需要重写抽象服务方法。
 */
public abstract class GenericServlet 
    implements Servlet, ServletConfig, java.io.Serializable
{
    private static final String LSTRING_FILE = "javax.servlet.LocalStrings";
    private static ResourceBundle lStrings =
        ResourceBundle.getBundle(LSTRING_FILE);

    private transient ServletConfig config;
    

    /**
     *
     * 什么也不做。所有servlet初始化都是由其中一个init方法完成的。
     *
     */
    public GenericServlet() { }
    
    
    /**
     * 由servlet容器调用,以指示servlet正在退出服务。
     */
    public void destroy() {
    }
    
    
    /**
     * 返回一个包含命名初始化参数值的字符串,如果参数不存在则返回null。
     * 提供这种方法是为了方便。它从servlet的ServletConfig对象获取指定参数的值。
     */ 
    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);
    }
    
    
   /**
    * 以String对象的枚举形式返回servlet初始化参数的名称,如果servlet没有初始化参数,则返回空枚举。
    * 提供这种方法是为了方便。它从servlet的ServletConfig对象获取参数名。
    */
    public Enumeration<String> getInitParameterNames() {
        ServletConfig sc = getServletConfig();
        if (sc == null) {
            throw new IllegalStateException(
                lStrings.getString("err.servlet_config_not_initialized"));
        }

        return sc.getInitParameterNames();
    }   
     

    /**
     * 返回servlet的ServletConfig对象。
     */    
    public ServletConfig getServletConfig() {
   		return config;
    }
 
    
    /**
     * 返回对servlet在其中运行的ServletContext的引用。
     * 提供这种方法是为了方便。它从servlet的ServletConfig对象获取上下文。
     */
    public ServletContext getServletContext() {
        ServletConfig sc = getServletConfig();
        if (sc == null) {
            throw new IllegalStateException(
                lStrings.getString("err.servlet_config_not_initialized"));
        }

        return sc.getServletContext();
    }


    /**
     * 返回有关servlet的信息,如作者、版本和版权。默认情况下,此方法返回一个空字符串。重写此方法以使其返回一个有意义的值。
     */    
    public String getServletInfo() {
        return "";
    }


    /**
     * 由servlet容器调用,以指示servlet正在被放入服务中。
     * 这个实现存储了它从servlet容器接收到的ServletConfig对象,以供以后使用。
     * 当重写这种形式的方法时,调用super.init(config)。
     */
    public void init(ServletConfig config) throws ServletException {
        this.config = config;
        this.init();
    }


    /**
     *一个方便的方法,可以被重写,这样就不需要调用super.init(config)。
     * 而不是重写init(ServletConfig),只需重写这个方法,它将被GenericServlet调用。
     * init (ServletConfig配置)。ServletConfig对象仍然可以通过getServletConfig来检索。
     */
    public void init() throws ServletException {

    }
    

    /**
     * 将指定的消息写入servlet日志文件,并以servlet的名称作为前置。
     */     
    public void log(String msg) {
    getServletContext().log(getServletName() + ": "+ msg);
    }
   
   
    /**
     * 将给定Throwable异常的解释性消息和堆栈跟踪写入servlet日志文件,并以servlet名称为前缀。
     */   
    public void log(String message, Throwable t) {
    getServletContext().log(getServletName() + ": " + message, t);
    }
    
    
    /**
     * 由servlet容器调用,以允许servlet响应请求。
     * 这个方法被声明为抽象的,所以子类,比如HttpServlet,必须覆盖它。
     */

    public abstract void service(ServletRequest req, ServletResponse res)
    throws ServletException, IOException;
    

    /**
     * 返回此servlet实例的名称。
     */
    public String getServletName() {
        ServletConfig sc = getServletConfig();
        if (sc == null) {
            throw new IllegalStateException(
                lStrings.getString("err.servlet_config_not_initialized"));
        }

        return sc.getServletName();
    }
}

3. HttpServlet

HttpServlet是用HTTP协议实现的Servlet的基类,写Servlet时直接继承它就可以了,不需要再从头实现Servlet接口。

HttpServlet是跟协议有关的,所以我们就关注一下如何处理请求。

HttpServlet的重点主要在service中,在service方法中首先将ServletRequestServletResponse转换为HttpServletRequestHttpServletResponse,然后根据Http请求的类型不同将请求路由到了不同的处理方法

    @Override
    public 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和response类型
        request = (HttpServletRequest) req;
        response = (HttpServletResponse) res;
		// 调用http的处理方法
        service(request, response);
    }   

	/**
     * 从公共服务方法接收标准HTTP请求,并将其分派给该类中定义的doXXX方法。
     * 该方法是Servlet的http特定版本Servlet. service方法。不需要重写这个方法。
     */
    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不支持if-modified-since,则无需进一步执行昂贵的逻辑
                doGet(req, resp);
            } else {
                // 获取请求头中的if-modified-since时间
                long ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
                if (ifModifiedSince < lastModified) {
                    // 如果servlet修改时间较晚,则调用doGet()
                    // 向下舍入最近的秒,以进行正确比较 
                    // ifModifiedSince为-1将始终小于lastModified
                    maybeSetLastModified(resp, lastModified);
                    doGet(req, resp);
                } else {
                    // 返回状态码为304(未修改)
                    resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
                }
            }

        } else if (method.equals(METHOD_HEAD)) {
            // 获取最后修改时间
            long lastModified = getLastModified(req);
            // 设置响应头中的最后修改时间
            maybeSetLastModified(resp, lastModified);
            // 调用doHead()
            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 {
            // 注意,这意味着没有servlet支持该服务器上任何地方请求的任何方法。
            String errMsg = lStrings.getString("http.method_not_implemented");
            Object[] errArgs = new Object[1];
            errArgs[0] = method;
            errMsg = MessageFormat.format(errMsg, errArgs);
            // 返回状态码为501(未实现)
            resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
        }
    }

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

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

相关文章

《数据结构》实验报告-实验一 线性结构及其应用

《数据结构》实验报告-实验一 线性结构及其应用 一、问题分析 题目要求收集两个班的学生成绩信息并按降序排列&#xff0c;其中每个学生的数据包括班级&#xff0c;学号和成绩信息&#xff0c;需要用一个结构体作为整体存储。并且数据是可以不断添加进来的&#xff0c;可以用…

c语言实现b树

概述&#xff1a;B 树&#xff08;B-tree&#xff09;是一种自平衡的搜索树数据结构&#xff0c;广泛应用于数据库和文件系统等领域。它的设计旨在提供一种高效的插入、删除和查找操作&#xff0c;同时保持树的平衡&#xff0c;确保各个节点的深度相差不大。 B 树的特点包括&a…

Vue keep-alive的使用和原理解析

✨ 专栏介绍 在当今Web开发领域中&#xff0c;构建交互性强、可复用且易于维护的用户界面是至关重要的。而Vue.js作为一款现代化且流行的JavaScript框架&#xff0c;正是为了满足这些需求而诞生。它采用了MVVM架构模式&#xff0c;并通过数据驱动和组件化的方式&#xff0c;使…

基于ssm的中文学习系统的设计与实现+jsp论文

摘 要 现代经济快节奏发展以及不断完善升级的信息化技术&#xff0c;让传统数据信息的管理升级为软件存储&#xff0c;归纳&#xff0c;集中处理数据信息的管理方式。本中文学习系统就是在这样的大环境下诞生&#xff0c;其可以帮助管理者在短时间内处理完毕庞大的数据信息&am…

Linux工具-搭建文件服务器

当我们使用linux系统作为开发环境时&#xff0c;经常需要在Linux系统之间、Linux和Windows之间传输文件。 对少量文件进行传输时&#xff0c;可以使用scp工具在两台主机之间实现文件传输&#xff1a; rootubuntu:~$ ssh --help unknown option -- - usage: ssh [-46AaCfGgKkMN…

C语言辨析——这个字符串长度是多少?

1. 问题 请问字符串"\tac\b\b\x41\nc\104\""的长度是多少&#xff1f; 2. 解答 该字符串的长度为10。这10个字符分别是水平制表符\t&#xff0c;a&#xff0c;c&#xff0c;两个退格符\b&#xff0c;\x41对应的字符’A&#xff0c;换行符\n&#xff0c;c&…

R语言【paleobioDB】——pbdb_subtaxa():统计指定类群下的子类群数量

Package paleobioDB version 0.7.0 paleobioDB 包在2020年已经停止更新&#xff0c;该包依赖PBDB v1 API。 可以选择在Index of /src/contrib/Archive/paleobioDB (r-project.org)下载安装包后&#xff0c;执行本地安装。 Usage pbdb_subtaxa (data, do.plot, col) Arguments…

NLP论文阅读记录 - 2021 | WOS 基于动态记忆网络的抽取式摘要

文章目录 前言0、论文摘要一、Introduction1.1目标问题1.2相关的尝试1.3本文贡献 二.前提三.本文方法四 实验效果4.1数据集4.2 对比模型4.3实施细节4.4评估指标4.5 实验结果4.6 细粒度分析 五 总结思考 前言 Extractive Summarization Based on Dynamic Memory Network&#xf…

【学习iOS高质量开发】——熟悉Objective-C

文章目录 一、Objective-C的起源1.OC和其它面向对象语言2.OC和C语言3.要点 二、在类的头文件中尽量少引用其他头文件1.OC的文件2.向前声明的好处3.如何正确引入头文件4.要点 三、多用字面量语法&#xff0c;少用与之等价的方法1.何为字面量语法2.字面数值3.字面量数组4.字面量字…

chrome浏览器开启硬件加速无法打开提示“此设置有你的管理员管理“

chrome浏览器开启硬件加速无法打开提示"此设置有你的管理员管理" winR 输入regedit 打开注册表注册表搜索 计算机\HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Google\Chrome删除 HardwareAccelerationModeEnabled重启Chrome浏览器。打开Chrome浏览器&#xff0c;查看设置…

【Java数据结构 -- 实现双链表的接口方法】

双链表 1.双链表2.双链表的创建3.双链表的头插节点4.双链表尾插5.双链表根据索引找节点6.双链表根据索引插入节点7.双链表删除值为key的节点8.删除所有值为key的节点9.双链表是否包含值为key节点10.双链表大小11.清空双链表12.打印双链表 1.双链表 双链表是一种数据结构&#…

【MATLAB】 SSA奇异谱分析信号分解算法

有意向获取代码&#xff0c;请转文末观看代码获取方式~ 1 基本定义 SSA奇异谱分析&#xff08;Singular Spectrum Analysis&#xff09;是一种处理非线性时间序列数据的方法&#xff0c;可以对时间序列进行分析和预测。 它基于构造在时间序列上的特定矩阵的奇异值分解&#…

部署YUM仓库及NFS共享存储

引言&#xff1a; 学习YUM 软件仓库&#xff0c;可以完成安装、卸载、自动升级 rpm 软件包等任务&#xff0c;能够自动 查找并解决 rpm 包之间的依赖关系&#xff0c;而无须管理员逐个、手工地去安装每个 rpm 包&#xff0c;使管理员在维护大量 Linux 服务器时更加轻松自如。特…

20240116-【UNITY 学习】增加滑动功能

替换脚本PlayerMovement_02.cs using System.Collections; using System.Collections.Generic; using UnityEngine;public class PlayerMovement_03 : MonoBehaviour {private float moveSpeed; // 玩家移动速度public float walkSpeed 7; // 行走速度public float sprintSpee…

竞赛保研 基于深度学习的水果识别 设计 开题 技术

1 前言 Hi&#xff0c;大家好&#xff0c;这里是丹成学长&#xff0c;今天做一个 基于深度学习的水果识别demo 这是一个较为新颖的竞赛课题方向&#xff0c;学长非常推荐&#xff01; &#x1f9ff; 更多资料, 项目分享&#xff1a; https://gitee.com/dancheng-senior/pos…

图像处理:孤立点的检测

图像处理-孤立点的检测 孤立点的检测在图像处理中通常涉及到检测图像中的突变或者边缘&#xff0c;而使用二阶导数是一种常见的方法。一阶导数可以帮助找到图像中的边缘&#xff0c;而二阶导数则有助于检测边缘上的峰值&#xff0c;这些峰值可能对应于孤立点或者特殊的图像结构…

2024美赛数学建模思路 - 案例:FPTree-频繁模式树算法

文章目录 算法介绍FP树表示法构建FP树实现代码 建模资料 ## 赛题思路 &#xff08;赛题出来以后第一时间在CSDN分享&#xff09; https://blog.csdn.net/dc_sinor?typeblog 算法介绍 FP-Tree算法全称是FrequentPattern Tree算法&#xff0c;就是频繁模式树算法&#xff0c…

帆软笔记-决策表报对象使用(两表格联动)

效果描述如下&#xff1a; 数据库中有个聚合商表&#xff0c;和一个储能表&#xff0c;储能属于聚合商&#xff0c;桩表中有个字段是所属聚合商。 要求帆软有2个表格&#xff0c;点击某个聚合商&#xff0c;展示指定的储能数据。 操作&#xff1a; 帆软选中表格单元&#xf…

Windows Server 2019配置DNS服务器

正文共&#xff1a;1234 字 31 图&#xff0c;预估阅读时间&#xff1a;1 分钟 我们在给Windows Server添加角色和功能时&#xff0c;会发现有一项“远程桌面服务安装”&#xff0c;它的介绍为“为虚拟桌面基础结构&#xff08;Virtual Desktop Infrastructure&#xff0c;VDI&…

PyTorch Tutorial 2.0

这里是对于PyTorch Tutorial-CSDN博客的补充&#xff0c;但是与其相关的NLP内容无关&#xff0c;只是一些基础的PyTorch用法的记录&#xff0c;主要目的是能够自己生成一些模拟的数据集。先介绍随机数的目的是因为based on随机数方法。 当然在看随机数的方法的时候&#xff0c…