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

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` 属性。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C++中的栈(Stack)和堆(Heap)

在C中&#xff0c;堆&#xff08;heap&#xff09;和栈&#xff08;stack&#xff09;是两种用于存储数据的内存区域。理解它们的原理和区别&#xff0c;对于优化代码性能和确保代码的安全性至关重要。以下是对C中堆栈的详细解析&#xff0c;包括它们的分配方式、优缺点、应用场…

群控系统服务端开发模式-应用开发-前端登录接口开发

一、修改验证方法 1、修改验证器 loginRules: {username: [{required: true, trigger: blur, validator: validateUsername}],password: [{required: true, trigger: blur, validator: validatePassword}],captcha_code: [{required: true, trigger: blur, validator: validat…

游戏引擎学习第10天

视频参考:https://www.bilibili.com/video/BV1LyU3YpEam/ 介绍intel architecture reference manual 地址:https://www.intel.com/content/www/us/en/developer/articles/technical/intel-sdm.html RDTS&#xff08;读取时间戳计数器&#xff09;指令是 x86/x86_64 架构中的…

MySQL查询某个数据库中特定表的空间占用大小

如果您也想要查询某个数据库中特定表的空间占用大小&#xff0c;包括数据和索引的大小&#xff0c;那么您可以使用以下SQL查询。这个查询将显示特定表在数据库中的数据大小、索引大小以及总大小。 SELECT table_name AS Table,ROUND(((data_length index_length) / 1024 / 10…

SystemVerilog学习笔记(十一):接口

在Verilog中&#xff0c;模块之间的通信是使用模块端口指定的。 Verilog模块连接的缺点 声明必须在多个模块中重复。存在声明不匹配的风险。设计规格的更改可能需要修改多个模块。 接口 SystemVerilog引入了 interface 结构&#xff0c;它封装了模块之间的通信。一个 inter…

el-input 正则表达式校验输入框不能输入汉字

<el-form :model"data1" :rules"rules" ref"ruleForm" label-width"210px" class"demo-ruleForm"><el-form-item label"锯路&#xff1a;" prop"sawKref"><el-input class"inptWid…

Pikachu[暴力破解:token防爆破]

暴力破解:token防爆破 校验方式&#xff1a; 请求中添加token防止爆破&#xff0c;登录时需携带服务器上一次加载时发送的token进行校验 解决&#xff1a; burp--intruder模块设置中使用Grep-Extract功能提取页面中的token&#xff0c;并将载荷类型更改为递归查询[Recursiv…

Springboot如何打包部署服务器

文章目的&#xff1a;java项目打包成jar包或war包&#xff0c; 放在服务器上去运行 一、编写打包配置 1. pom.xml 在项目中的pom.xml文件里面修改<build>...</build>的代码 >> 简单打包成Jar形式&#xff0c;参考示例&#xff1a; <build><fina…

flink 同步oracle11g数据表到pg库

1. 关闭防火墙和selinux systemctl stop firewalld systemctl disable firewalld systemctl status firewalldvi /etc/selinux/config 修改为disabled2.安装java8 yum list java-1.8* yum install java-1.8.0-openjdk* -yjava -version3.下载和部署postgresql 看需求安装pg库…

机器学习: LightGBM模型(优化版)——高效且强大的树形模型

LightGBM&#xff08;Light Gradient Boosting Machine&#xff09;是一种基于梯度提升决策树&#xff08;GBDT&#xff09;的框架&#xff0c;由微软提出。它具有高效的训练速度、低内存占用、支持并行和GPU加速等特点&#xff0c;非常适合大规模数据的训练任务&#xff0c;尤…

mysql中的EXISTS和NOT EXISTS使用详解

本文来编写一个实例说下mysql中的EXISTS和NOT EXISTS使用详解 文章目录 exists用法SQL中in, not in, exists, not exists的区别使用实例本文小结 exists用法 exists: 如果括号内子查询语句返回结果不为空&#xff0c;说明where条件成立&#xff0c;就会执行主SQL语句。如果括号…

idea 弹窗 delete remote branch origin/develop-deploy

想删除远程分支&#xff0c;就选delete&#xff0c;仅想删除本地分支&#xff0c;选cancel&#xff1b; 在 IntelliJ IDEA 中遇到弹窗提示删除远程分支 origin/develop-deploy&#xff0c;这通常是在 Git 操作过程中出现的情况&#xff0c;可能是在执行如 git branch -d 或其他…

基于微信小程序的高校实习管理系统设计与实现,LW+源码+讲解

摘 要 信息数据从传统到当代&#xff0c;是一直在变革当中&#xff0c;突如其来的互联网让传统的信息管理看到了革命性的曙光&#xff0c;因为传统信息管理从时效性&#xff0c;还是安全性&#xff0c;还是可操作性等各个方面来讲&#xff0c;遇到了互联网时代才发现能补上自…

Spring Boot 牛刀小试 org.springframework.boot:spring-boot-maven-plugin:找不到类错误

今天看了下书翻了下Spring Boot的用法&#xff0c;下载idea后&#xff0c; 反复出现org.springframework.boot:spring-boot-maven-plugin:找不到类错误&#xff0c;后来看了下调试窗口&#xff0c;发现是连不上maven的网站443错误&#xff0c;解决思路很简单&#xff0c;把ide连…

k-近邻算法(K-Nearest Neighbors, KNN)详解:机器学习中的经典算法

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…

UE5 umg学习(四) 将UI控件显示到关卡中

视频资料 7、将UI控件渲染到关卡_哔哩哔哩_bilibili 在前三节里&#xff0c;创建了用户的控件蓝图Widget_BP 目标是运行的时候&#xff0c;开始运行这个蓝图&#xff0c;因此需要在开始事件触发运行 首先&#xff0c;回到主页&#xff0c;点击关卡蓝图 要从事件开始运行时 …

StarRocks Summit Asia 2024 全部议程公布!

随着企业数字化转型深入&#xff0c;云原生架构正成为湖仓部署的新标准。弹性扩展、资源隔离、成本优化&#xff0c;帮助企业在云上获得了更高的灵活性和效率。与此同时&#xff0c;云原生架构也为湖仓与 AI 的深度融合奠定了基础。 在过去一年&#xff0c;湖仓技术与 AI 的结…

【CSS】opacity 影响 z-index 不生效

准备知识 一般来说&#xff0c;z-index 不生效的原因有&#xff1a; 父元素的 position 属性&#xff1a; z-index 只对 position 属性为 relative、absolute 或 fixed 的元素有效。 其他元素的 z-index&#xff1a; 如果页面中有其他元素也设置了较高的 z-index&#xff0c;…

2024 年(第 7 届)“泰迪杯”数据分析技能赛B 题 特殊医学用途配方食品数据分析 完整代码 结果 可视化分享

一、背景特殊医学用途配方食品简称特医食品&#xff0c;是指为满足进食受限、消化吸收障碍、代谢素乱或者特定疾病状态人群对营养素或者膳食的特殊需要&#xff0c;专门加工配置而成的配方食品&#xff0c;包括0月龄至12月龄的特殊医学用途婴儿配方食品和适用于1岁以上的特殊医…

【MYSQL】数据库日志 (了解即可)

一、错误日志 可以通过 tail查看文件的日志的&#xff0c;如果发生错误&#xff0c;就会在日志里出现问题。 二、二进制日志&#xff08;binlog&#xff09; BINLOG记录了insert delete update 以及 alter create drop 等语句。作用是灾难时的数据恢复&#xff0c;还有就是主…