Struts源码阅读——三个常用的辅助类DispatchAction

news2025/1/6 19:58:29

Struts源码阅读——三个常用的辅助类

紧接前文,我们来阅读org.apache.struts.actions包中三个常用类的源码。

DispatchActionLookupDispatchActionMappingDispatchAction 是 Struts 1 框架中的三个常用的辅助类,用来简化 Action 类中的请求分发。

这三个文件可以从框架的核心库 struts-corejar 包中找到。

全类名是org.apache.struts.actions.xxxAction


DispatchAction.java

类图

image-20241108155357333

源码

这是一个抽象类,派生类(后端控制器)继承该类,但是不会覆盖其方法,该类并无抽象方法,仅仅是增加多个后端控制方法罢了。

例如,增删改查的业务逻辑,通常写上 4 个后端控制器类:CreateActionRetrieveActionUpdateActionDeleteAction
这些后端控制器类都继承 Action 类,实现执行函数,也就是覆盖 Action 类的 execute 函数。

public ActionForward execute(
    ActionMapping mapping,
    ActionForm form,
    HttpServletRequest request,
    HttpServletResponse response) throws Exception

这样的设计导致后端控制器类数量太多,并且没有体现出聚合性、封装性。可以把这几个类的 execute 方法,封装在同一个类中,当然,函数声明重复了,所以要根据功能把这些函数的函数名称修改一下,例如:create 函数、retrieve 函数、update 函数、delete 函数。

前端控制器 org.apache.struts.action.ActionServlet 的控制流程当然没有改变,它会调用后端控制器的 execute 函数。

DispatchAction 的设计思路

那么,DispatchAction 这个抽象类的 execute 方法的实现,就是根据浏览器端(客户端)发送过来的 URL 或者 queryString 来完成分发(dispatch)!
DispatchAction 这个类的 execute 方法的具体实现,就是根据查询字符串 (queryString) 中的某个参数数据完成分发,例如,execute 方法可以分发到 createretrieveupdatedelete 方法。

既然我们已经理解了 DispatchAction 类的 execute 函数的设计需求,那么,同学们,你们会写出来 DispatchAction 类的 execute 函数吗?

两个关键问题

有两个问题需要知道:

  1. 后端控制器类继承 DispatchAction 类,增加多个控制函数,函数名称未知(输入输出参数都是不变的)。
  2. 根据查询字符串中的什么参数的值来完成转发(dispatch)?
上面的回答

在 Struts 配置文件中指定使用什么参数,并自定义参数的逻辑名称。然后,由参数的值决定调用哪个控制函数,调用过程使用 Java 反射机制。

例如,Struts 配置文件:

<action path="/calc" type="action.CalcAction" name="calcForm" input="/calc.jsp" parameter="method"/>

calc 表单中的四个提交按钮,value代表了method所拥有的四个值:

<input type="submit" name="method" value="add"/>
<input type="submit" name="method" value="subtract"/>
<input type="submit" name="method" value="multiply"/>
<input type="submit" name="method" value="divide"/>

优化后的控制器设计

通过这种方法,AddActionSubtractActionMultiplyActionDivideAction 的后端控制器数量就被减少到只写一个后端控制器类:CalcAction,并继承自 DispatchAction,在 CalcAction 中定义四个控制函数即可:

public ActionForward add(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception
public ActionForward subtract(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception
public ActionForward multiply(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception
public ActionForward divide(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception
DispatchAciton源码
package org.apache.struts.actions;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import java.util.HashMap;

public abstract class DispatchAction extends BaseAction {
    protected static Log log = LogFactory.getLog(DispatchAction.class);
    protected Class clazz = this.getClass();
	
	// methods这个map集合是缓存的目的,因为反射机制有点慢。
	// key: String method name, value: Method object
	// 声明为HashMap<String,Method> methods更好,类型安全,更准确,否者HashMap,鬼知道这个集合里面都有啥。
    protected HashMap methods = new HashMap();  

    // execute函数的输入参数的类型,反射机制使用。同时,也是扩展的控制函数的参数类型。
    protected Class[] types =
        {
            ActionMapping.class, ActionForm.class, HttpServletRequest.class,
            HttpServletResponse.class
        };
	
	// 最重要的算法实现,完成dispatch
    public ActionForward execute(ActionMapping mapping, ActionForm form,
        HttpServletRequest request, HttpServletResponse response)
        throws Exception {

        // 从配置文件中获取parameter的名,例如,method
        String parameter = getParameter(mapping, form, request, response);

        // 从请求对象中,获取由parameter的值指定的控制函数的名称
		// String name = request.getParameter(parameter)
        String name = getMethodName(mapping, form, request, response, parameter);	// 考试内容
		
		// name的值就是控制函数的名称,例如add,subtract,multipy,divide之类的。

        // Prevent recursive calls, 避免递归,扩展的控制函数的名称不能是execute
        if ("execute".equals(name) || "perform".equals(name)) {
            String message =
                messages.getMessage("dispatch.recursive", mapping.getPath());
            log.error(message);
            throw new ServletException(message);
        }

		// 动态调用控制函数,完成dispatch! 
		// 控制流程是前端控制器调用CalcAction类的execute函数(继承自DispatchAction)
		// 然后execute函数将调用转发到add函数,subtract函数等等。
		
        // Invoke the named method, and return the result
        return dispatchMethod(mapping, form, request, response, name);
    }

    
    protected ActionForward dispatchMethod(ActionMapping mapping,
        ActionForm form, HttpServletRequest request,
        HttpServletResponse response, String name)
        throws Exception {
      
        // Identify the method object to be dispatched to
        Method method = null;

        try {
            method = getMethod(name);	// 根据函数名称,找到函数对象。
        } catch (NoSuchMethodException e) {
            String message =
                messages.getMessage("dispatch.method", mapping.getPath(), name);
            log.error(message, e);
            String userMsg =
                messages.getMessage("dispatch.method.user", mapping.getPath());
            throw new NoSuchMethodException(userMsg);
        }

        ActionForward forward = null;

        try {
			// Java反射机制,执行某个对象的函数,动态调用。考试重点。
            Object[] args = { mapping, form, request, response };
            forward = (ActionForward) method.invoke(this, args);

        }
		
        // Return the returned ActionForward instance
        return (forward);
    }

    protected String getParameter(ActionMapping mapping, ActionForm form,
        HttpServletRequest request, HttpServletResponse response)
        throws Exception {

        // 从struts-config.xml配置文件中读取action元素的parameter属性的值。
		// 当然是ActionMapping类封装的功能了。ActionMapping类不考。
        String parameter = mapping.getParameter();	// 算法重点

        return parameter;
    }

    // 根据函数名称获取函数对象,需要调用Class类的的getMethod函数,Java的反射机制!
    protected Method getMethod(String name)
        throws NoSuchMethodException {
		// 同步,加锁,这个性能不好,如何解决?不使用同步代码可以吗?
        synchronized (methods) {	// Action是单实例对象,注意methods线程安全。
            Method method = (Method) methods.get(name);

            if (method == null) {
                method = clazz.getMethod(name, types);	// 重点,Java反射机制
				// 保存到Map集合中,下次再调用getMethod函数直接从Map集合中读取,不再调用反射。
                methods.put(name, method);	
            }

            return (method);
        }
    }

    
    protected String getMethodName(ActionMapping mapping, ActionForm form,
        HttpServletRequest request, HttpServletResponse response,
        String parameter) throws Exception {
        //从请求对象中获取参数数据,HttpServletRequest中的获取参数的方法一定要掌握,考试重点。
        return request.getParameter(parameter);
    }
}

功能:

DispatchAction 是 Struts 1 提供的一个 Action 类,用于将多个业务逻辑分派到同一个 Action 中处理。它允许你在一个类中定义多个方法,并根据请求参数调用不同的方法。

注意事项:

在 JSP 页面中指定 method 参数(或其他指定参数)来区分调用的方法。例如:<html:link action="/example.do?method=add">Add</html:link>

优点和限制

  • 优点:减少了创建多个 Action 类的需求,可以将同一模块的操作集中在一个类中,提升了代码组织性。

  • 限制:传递的 method 参数必须与方法名严格一致,且方法必须是 public 且没有参数的。


LookupDispatchAction.java

类图

image-20241108155704151

源码

LookupDispatchAction 设计分析

DispatchAction 的问题

DispatchAction 类的转发逻辑相对简单,但也存在一些问题。
例如,以下 HTML 代码中,提交按钮的 value 属性值就是函数名称:

<input type="submit" name="method" value="add"/>

这里的按钮文本直接对应了后端控制器的方法名称,这样做存在以下问题:

  1. 安全性差:函数名称暴露在客户端。
  2. 代码泄漏:方法名暴露可能会被恶意用户篡改或猜测。
  3. 特殊字符问题:按钮的文本可能是中文或包含空格等特殊字符,可能会导致问题。

因此,必须对这种实现方式进行改进。

LookupDispatchAction 解决方案

LookupDispatchAction 类继承自 DispatchAction,并继承了 DispatchAction 类的 execute 函数,但它对 execute 函数进行了增强和改进。

LookupDispatchAction 中,主要做了以下改进:

  1. 获取控制函数的名称LookupDispatchAction 通过 getMethodName() 函数获取控制函数名称。
  2. 反射机制完成 dispatch:利用反射机制来进行函数的调用。

虽然 LookupDispatchAction 没有改变 dispatch 逻辑(即根据函数名称进行分发),但是它改写了 getMethodName 函数,从而提供了一个更安全、灵活的方式来获取函数名称。

getMethodName 的实现

DispatchAction 类的 getMethodName 函数非常简单,通过配置文件指定参数名称:

<action path="/calc" type="action.CalcAction" name="calcForm" input="/calc.jsp" parameter="method"/>

客户端提交指定参数的值,也就是函数名称:

<input type="submit" name="method" value="add"/>

这个方法存在安全性和灵活性的问题,因此需要改进。

引入资源文件

为了提高灵活性和支持国际化,Struts 支持使用资源文件。在 struts-config.xml 中,可以声明资源文件:

<message-resources parameter="ApplicationResources" />

然后在类加载路径中创建 ApplicationResources.properties 文件,文件内容如下:

button.add=Add
button.subtract=Subtract
button.multiply=Multiply
button.divide=Divide

在资源文件中,name(即键)通常是程序内部使用的标识符,而 value(即值)通常是显示给用户的文本(例如按钮的文本)。资源文件中的值可以是中文字符,name 是唯一的,value 通常也是唯一的。

提交按钮的国际化实现

在 HTML 表单中使用资源文件的内容,代码如下:

<html:form action="/calc">
    <html:submit property="method">
        <bean:message key="button.add"/>
    </html:submit>
    <html:submit property="method">
        <bean:message key="button.subtract"/>
    </html:submit>
</html:form>
CalcAction 类的改进

在这种设计下,CalcAction 类不再继承 DispatchAction,而是继承 LookupDispatchAction
LookupDispatchAction 继承自 DispatchAction,并改进了 getMethodName 的实现,使得控制函数的名称不再直接暴露在客户端。

体现 “lookup” 的机制

LookupDispatchAction 类的核心思想是通过字典映射来查找函数名称。它定义了一个抽象方法 getKeyMethodMap,返回一个映射(Map),将资源文件中的 key 映射到相应的控制函数名称。

例如,getKeyMethodMap 可以如下实现:

@Override
public Map getKeyMethodMap() {
    Map<String, String> map = new HashMap<>();
    map.put("button.add", "add");
    map.put("button.subtract", "subtract");
    return map;
}

这个映射返回一个 Map,其中 key 是资源文件中的 key(例如 button.add),而 value 是相应的方法名称(例如 add)。

getMethodName 方法的改写

DispatchAction 类中,getMethodName 是一个重要的函数,我们需要对其进行改写(override)。
改写后的 getMethodName 根据参数名称(例如 method)来获取客户端提交的参数值,然后通过反向查找获取函数名称。

protected String getMethodName(
    ActionMapping mapping, 
    ActionForm form, 
    HttpServletRequest request, 
    HttpServletResponse response, 
    String parameter) throws Exception

具体实现过程如下:

  1. 根据 parameter 指定的浏览器端提交的参数名称(例如 parameter="method"),从请求对象中获取该参数的值。
  2. 根据该值,在资源文件中的 key-value 映射中查找对应的 keyName
  3. 根据 keyName 查找到函数名称,并最终调用相应的控制函数。

通过 LookupDispatchAction 的设计,我们不仅提高了安全性,避免了暴露函数名称,还通过资源文件实现了国际化和灵活的参数配置。此设计利用字典(映射集合)来查找函数名称,并通过反射机制实现动态方法调用,从而提高了代码的封装性、可维护性和安全性。

LookupDispatchAction源码
package org.apache.struts.actions;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.struts.Globals;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.config.MessageResourcesConfig;
import org.apache.struts.config.ModuleConfig;
import org.apache.struts.util.MessageResources;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Locale;
import java.util.Map;

public abstract class LookupDispatchAction extends DispatchAction {

    private static final Log LOG = LogFactory.getLog(LookupDispatchAction.class);
    protected Map localeMap = new HashMap(); 	// Map<Locale,Map<String,String>>
    protected Map keyMethodMap = null;			// Map<String,String>

    private Map initLookupMap(HttpServletRequest request, Locale userLocale) {
		
        Map lookupMap = new HashMap();
        this.keyMethodMap = this.getKeyMethodMap();

        // 获取模块配置,struts 支持模块开发(一个项目通常会分解为多个模块)
        // 可以理解有多个类似struts-config.xml的配置文件。
        ModuleConfig moduleConfig =
            (ModuleConfig) request.getAttribute(Globals.MODULE_KEY);  // 通常根据uri获取模块配置

        // 读取该模块的配置文件中的资源文件的配置。
        // 在struts-config.xml文件中可以有多个这样的资源配置,例如在struts-config.xml中的声明
        //  <message-resources parameter="ApplicationResources" />
        //  <message-resources key="aaa" parameter="res.aaa.AResources" />
        //  <message-resources key="bbb" parameter="res.bbb.BResources" />

        // 获取所在模块的资源配置信息。一个模块可以有多个资源文件,见上面的配置信息。
        // MessageResourcesConfig对象有parameter和key属性。
        MessageResourcesConfig[] mrc = 
            moduleConfig.findMessageResourcesConfigs();

        // 这个注释不准确。Look through all module's MessageResources
        // 遍历每个message-resources
        for (int i = 0; i < mrc.length; i++) {
            MessageResources resources =
                this.getResources(request, mrc[i].getKey());

            // 开始处理资源文件中的一部分name:value pair数据。主要是根据函数字典进行数据遍历。
            // Look for key in MessageResources
            Iterator iter = this.keyMethodMap.keySet().iterator();

            while (iter.hasNext()) {
                String key = (String) iter.next();
                String text = resources.getMessage(userLocale, key);	// 支持国际化

                // Found key and haven't added to Map yet, so add the text
                if ((text != null) && !lookupMap.containsKey(text)) {
                    lookupMap.put(text, key);	// 考试内容,注意是text:key映射,不是key:text映射!
            }
        }

        return lookupMap;
    }

    // 派生类必须覆盖这个抽象函数
    protected abstract Map getKeyMethodMap();


    // 参数keyName就是浏览器端提交的参数信息,例如:method=Add
    // keyName是Add,根据这个value,找到button.add这个key
    protected String getLookupMapName(HttpServletRequest request,
        String keyName, ActionMapping mapping)
        throws ServletException {
        // Based on this request's Locale get the lookupMap
        Map lookupMap = null;

        synchronized (localeMap) {
            Locale userLocale = this.getLocale(request);	// 获取浏览器的区域语言,从Action类继承过来的。
            lookupMap = (Map) this.localeMap.get(userLocale);
            if (lookupMap == null) {
                lookupMap = this.initLookupMap(request, userLocale);
                this.localeMap.put(userLocale, lookupMap);
            }
        }

        // 从value:key映射集合中,获取key
        String key = (String) lookupMap.get(keyName);	// 资源文件中的value:key构成的映射集合

        // Find the method name
        String methodName = (String) keyMethodMap.get(key);	// 在函数字典中lookup up到函数名称

        return methodName;	// 返回函数名称
    }

    // 考试重点
    // LookupDispatchAction类的核心实现,根据浏览器提交的参数数据,以及函数字典,获取派发的函数名称!
    @Override
    protected String getMethodName(ActionMapping mapping, ActionForm form,
        HttpServletRequest request, HttpServletResponse response,
        String parameter) throws Exception {
			
        // 从浏览器端发送过来的参数获取标签文本、按钮文本之类的参数值
        String keyName = request.getParameter(parameter);

        if ((keyName == null) || (keyName.length() == 0)) {
            return null;
        }

        String methodName = getLookupMapName(request, keyName, mapping);

        return methodName;
    }
}

功能:

LookupDispatchActionDispatchAction 的扩展,主要用于国际化场景。它允许基于请求参数自动调用不同的方法,并且支持从资源文件中读取键值对,实现国际化。

注意事项:

需要重写 getKeyMethodMap() 方法,定义请求参数和方法名的映射关系。此映射关系可以用来支持不同语言的按钮文本映射到相应的操作方法。

优点和限制

  • 优点:适合需要根据不同语言自动映射的操作方法,使代码更加清晰。

  • 限制:比 DispatchAction 多了键值对配置的工作量,但更适合多语言需求的场景。


MappingDispatchAction.java

类图

image-20241108155723633

源码

同一个后端控制器对应多个 <action> 配置

在 Struts 框架中,一个后端控制器类可以对应多个 <action> 配置。也就是说,同一个后端控制器类可以有多个控制函数。例如,CalcAction 类可以有 addsubtractmultiplydivide 函数,而 DispatchAction 类的 execute 函数负责完成函数的分发(dispatch)。

如何实现函数的分发?

那么,如何实现这些控制函数的调用和转发呢?execute 函数是如何将请求转发到 addsubtractmultiplydivide 等不同的函数呢?

MappingDispatchAction 的改进

MappingDispatchAction 类改写了(覆盖)getMethodName 函数。这个函数返回的控制函数名称来自 <action> 元素的 parameter 属性的值。通过这个方法,MappingDispatchAction 能够根据请求的参数值动态决定调用哪个函数。

通过这种设计,可以将具有相关性和聚合性的多个函数封装在同一个后端控制器类中,并为该控制器类定义多个 <action> 路径。

示例:为不同的路径定义多个 <action>

举个例子,如果我们有一个 CalcAction 类,它包含了 addsubtractmultiplydivide 函数,我们可以通过以下方式在 struts-config.xml 中为每个函数定义一个路径:

<action path="/add" type="action.CalcAction" parameter="add"/>
<action path="/subtract" type="action.CalcAction" parameter="subtract"/>
<action path="/multiply" type="action.CalcAction" parameter="multiply"/>
<action path="/divide" type="action.CalcAction" parameter="divide"/>

在这个配置中,每个 <action> 元素对应了 CalcAction 中的一个函数,parameter 属性指定了要调用的控制函数的名称。

控制器类的改进

为了使得这个配置生效,CalcAction 类只需要继承 MappingDispatchAction 类,并且通过 parameter 属性来确定要调用的控制函数。由于 MappingDispatchAction 已经实现了动态分发的机制,parameter 属性直接决定了要调用的函数名称。

通过将多个函数封装在同一个后端控制器类中,并为该控制器类定义多个 <action> 路径,MappingDispatchAction 实现了一个灵活的解决方案,使得我们可以根据请求的不同路径动态调用不同的函数。这样,后端控制器类就不需要为每个操作定义单独的控制器类,减少了代码冗余,并提高了可维护性和灵活性。

MappingDispatchAction源码
package org.apache.struts.actions;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class MappingDispatchAction extends DispatchAction {
  
    // 这个函数没有存在的必要,直接继承DispatchAction类就可以了。
    // 毫无意义的覆盖。
    protected String getParameter(ActionMapping mapping, ActionForm form,
        HttpServletRequest request, HttpServletResponse response)
        throws Exception {

        return mapping.getParameter();

    }

    // MappingDispatchAction唯一有意义的函数,覆盖了DispatchAction类的getMethodName函数。
    protected String getMethodName(ActionMapping mapping, ActionForm form,
        HttpServletRequest request, HttpServletResponse response,
        String parameter) throws Exception {

        // 派发的控制函数的函数名称就是在<action>元素中parameter属性的值。
        return parameter;
    }
}

功能:

MappingDispatchAction 类似于 DispatchAction,但它使用了 ActionMapping 的属性 parameter 来确定调用的方法。它通过 ActionMapping 中的 parameter 值来找到相应的方法,避免在请求中直接使用 method 参数。

注意事项:

struts-config.xml 文件中配置 Action 时,设置 parameter 属性来指定映射参数。

优点和限制:

  • 优点:避免了在请求 URL 中暴露方法名,提升了安全性,适合不想公开请求参数的应用场景。

ected String getMethodName(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response,
String parameter) throws Exception {

    // 派发的控制函数的函数名称就是在<action>元素中parameter属性的值。
    return parameter;
}

}


### 功能: 
`MappingDispatchAction` 类似于 `DispatchAction`,但它使用了 ActionMapping 的属性 `parameter` 来确定调用的方法。它通过 `ActionMapping` 中的 `parameter` 值来找到相应的方法,避免在请求中直接使用 `method` 参数。

### 注意事项:
在 `struts-config.xml` 文件中配置 Action 时,设置 `parameter` 属性来指定映射参数。

### 优点和限制:
- **优点**:避免了在请求 URL 中暴露方法名,提升了安全性,适合不想公开请求参数的应用场景。

- **限制**:需要在 `struts-config.xml` 中额外配置 `parameter` 属性。

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

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

相关文章

Linux设置Nginx开机启动

操作系统环境&#xff1a;CentOS 7 【需要 root 权限&#xff0c;使用 root 用户进行操作】 原理&#xff1a;利用 systemctl 管理服务 设置 Nginx 开机启动 需要 root 权限&#xff0c;普通用户使用 sudo 进行命令操作 原理&#xff1a;利用 systemctl 管理服务 1、新建…

C# WPF 记录DataGrid的表头顺序,下次打开界面时应用到表格中

效果&#xff1a; 代码实现 前端 <DataGrid x:Name"DataGrid1"<!--定义当列位置变化后的触发事件-->CanUserReorderColumns"True"ColumnReordered"DataGrid_ColumnReordered"rubyer:ControlHelper.FocusedForegroundBrush"{Stati…

Transformer-BiLSTM、Transformer、CNN-BiLSTM、BiLSTM、CNN五模型多变量回归预测

Transformer-BiLSTM、Transformer、CNN-BiLSTM、BiLSTM、CNN五模型多变量回归预测 目录 Transformer-BiLSTM、Transformer、CNN-BiLSTM、BiLSTM、CNN五模型多变量回归预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 吐血售&#xff01;聚划算&#xff01;Transforme…

面试官:如何设计一个能够支持高并发的系统?

强烈推荐 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站:人工智能 设计一个支持高并发的系统是一个系统工程&#xff0c;涉及多个层面的优化。以下逐一展开说明&#xff1a; 1. 分布式架…

企业数字化转型指南:如何通过价值流推动业务创新与变革

在全球企业加速数字化转型的浪潮中&#xff0c;企业领导者和技术人员必须理解数字化转型的核心不只是技术的应用&#xff0c;而是业务流程的彻底重塑。根据《价值流&#xff08;Value Streams&#xff09;》中的理论框架&#xff0c;数字化转型的关键在于价值流&#xff08;Val…

知识库管理系统:企业数字化转型的加速器

在数字化转型的大潮中&#xff0c;知识库管理系统&#xff08;KBMS&#xff09;已成为企业提升效率和创新能力的关键工具。本文将探讨知识库管理系统的定义、企业建立知识库的必要性&#xff0c;以及如何快速搭建企业知识库。 知识库管理系统是什么&#xff1f; 知识库管理系统…

Python 绘图工具详解:使用 Matplotlib、Seaborn 和 Pyecharts 绘制散点图

目录 数据可视化1.使用 matplotlib 库matplotlib 库 2 .使用 seaborn 库seaborn 库 3 .使用 pyecharts库pyecharts库 注意1. 确保安装了所有必要的库2. 检查Jupyter Notebook的版本3. 使用render()方法保存为HTML文件4. 使用IFrame在Notebook中显示HTML文件5. 检查是否有其他输…

JAVA学习日记(十五) 数据结构

一、数据结构概述 数据结构是计算机底层存储、组织数据的方式。 数据结构是指数据相互之间以什么方式排列在一起的。 数据结构是为了更加方便的管理和使用数据&#xff0c;需要结合具体的业务场景来进行选择。 二、常见的数据结构 &#xff08;一&#xff09;栈 特点&…

【C++】—掌握STL vector 类:“Vector简介:动态数组的高效应用”

文章目录 1.vector的介绍和使用1.1vector的介绍1.2 vector的特点1.3vector的使用1.3.1vector的定义1.3.2vector iterator的使用1.3.3vector 的空间增长问题1.3.4 vector 的增删查改1.3.5vector 迭代器失效问题 1.vector的介绍和使用 1.1vector的介绍 vector是一个顺序容器&am…

PTE-中间件安全

DOCKER环境&#xff0c;一般是80 8080 8081端口 1 apache位置扩展名解析漏洞 cd vulhub-master/httpd/apache_parsing_vulnerability/ docker-compose up -d 修改一句话的后缀 直接上传 蚁剑 2 CVE-2017-15715 docker-compose stop cd .. cd CVE-2017-15715/ dock…

Python用CEEMDAN-LSTM-VMD金融股价数据预测及SVR、AR、HAR对比可视化

全文链接&#xff1a;https://tecdat.cn/?p38224 分析师&#xff1a;Duqiao Han 股票市场是一个复杂的非线性系统&#xff0c;股价受到许多经济和社会因素的影响。因此&#xff0c;传统的线性或近线性预测模型很难有效、准确地预测股票指数的价格趋势。众所周知&#xff0c;深…

【Revit二次开发】创建Ribbon选项卡与带图标的按钮

效果图 创建一个叫做“开发的插件”的选项卡&#xff0c; 选项卡内有一个叫做“Hello”的图标按钮&#xff0c; 点击按钮后运行一个命令&#xff0c; 该命令弹出提示框“Hello Revit!”。 在此示例基础上&#xff0c;可以根据需要替换图标、文字、命令功能。 步骤 安装Revit…

Java面试要点18 - Java运行时多态与编译时多态

本文目录 一、引言二、运行时多态的实现三、编译时多态的实现四、多态与接口五、多态的实际应用六、总结 一、引言 多态是面向对象编程的三大特性之一&#xff0c;它允许我们以统一的方式处理不同类型的对象。Java中的多态分为两种&#xff1a;编译时多态&#xff08;重载&…

使用@react-three/fiber,@mkkellogg/gaussian-splats-3d加载.splat,.ply,.ksplat文件

前言 假设您正在现有项目中集成这些包&#xff0c;而该项目的构建工具为 Webpack 或 Vite。同时&#xff0c;您对 Three.js 和 React 有一定的了解。如果您发现有任何错误或有更好的方法&#xff0c;请随时留言。 安装 npm install three types/three react-three/fiber rea…

HBase理论_背景特点及数据单元及与Hive对比

本文结合了个人的笔记以及工作中实践经验以及参考HBase官网&#xff0c;我尽可能把自己的知识点呈现出来&#xff0c;如果有误&#xff0c;还请指正。 1. HBase背景 HBase作为面向列的数据库运行在HDFS之上&#xff0c;HDFS缺乏随机读写操作&#xff0c;HBase正是为此而出现。…

(Go基础)Go的运行流程步骤与包的概念

1. 快速入门 所有的go开发&#xff0c;都必须存在并包含在某一个包内 .go 是go语言程序的后缀名 1.1 编译 通过使用 go build 命令对该go文件进行编译&#xff0c;生成.exe文件 1.2 运行 运行刚刚生成出来的test.exe文件既可&#xff0c;不过并不不是双击&#xff0c;而是在…

蓝桥杯每日真题 - 第11天

题目&#xff1a;&#xff08;合并数列&#xff09; 题目描述&#xff08;14届 C&C B组D题&#xff09; 解题思路&#xff1a; 题意理解&#xff1a;给定两个数组&#xff0c;目标是通过若干次合并操作使两个数组相同。每次合并操作可以将数组中相邻的两个数相加&#xff…

手撸 chatgpt 大模型:简述 LLM 的架构,算法和训练流程

本节我们自顶向下看看大模型的相关概念&#xff0c;了解其基本架构以及从零手撸大模型的基本流程。自从 openai 释放了 chatgpt 后&#xff0c;人工智能就立马进入了大模型时代&#xff0c;我还记得在此之前 NLP 的处理主要依赖于深度学习的 LSTM&#xff0c;GRU 等模型架构。这…

FPGA实现PCIE3.0视频采集转千兆UDP网络输出,基于XDMA+RTL8211E架构,提供工程源码和技术支持

目录 1、前言工程概述免责声明 2、相关方案推荐我已有的PCIE方案我这里已有的以太网方案本博客方案的PCIE2.0版本 3、PCIE基础知识扫描4、工程详细设计方案工程设计原理框图电脑端视频QT上位机XDMA配置及使用XDMA中断模块FDMA图像缓存UDP视频组包发送UDP协议栈MAC数据缓冲FIFO组…

2024年第四届“网鼎杯”网络安全比赛---朱雀组Crypto- WriteUp

2024年第四届“网鼎杯”网络安全比赛---朱雀组Crypto-WriteUp Crypto&#xff1a;Crypto-2&#xff1a;Crypto-3&#xff1a; 前言&#xff1a;本次比赛已经结束&#xff0c;用于赛后复现&#xff0c;欢迎大家交流学习&#xff01; Crypto&#xff1a; Crypto-2&#xff1a; …