Struts2之拦截器

news2024/9/9 4:26:05

Struts2之拦截器

  • 1、Struts2体系架构
    • 1.1、执行流程
    • 1.2、核心接口和类
    • 1.3、流程简图
  • 2、Struts2拦截器
    • 2.1、使用拦截器的目的
    • 2.2、拦截器的简介
    • 2.3、拦截器的工作原理
    • 2.4、拦截器的使用
      • 2.4.1、创建自定义拦截器
      • 2.4.2、struts.xml中定义和配置拦截器
      • 2.4.3、Struts2默认拦截器
      • 2.4.4、拦截器栈
    • 2.5、例子

1、Struts2体系架构

以下图示:

在这里插入图片描述

1.1、执行流程

  • 用户发送request请求,请求会先经过一系列的过滤器Filter。
  • 过滤器放行后,经过核心控制器FilterDispatcher(旧版本,新版本为StrutsPrepareAndExecuteFilter),核心控制器会使用Action代理对象读取struts.xml配置文件,然后创建struts2控制器Action的实例。
  • 进入Action控制器之前会经过一系列的拦截器。
  • 拦截器放行后进入Action,根据返回的结果字符串result会选择相应的视图,在响应到客户端之前也会经过一系列的拦截器。

比如用户登录的场景:

==> 填写账号密码后点击提交按钮,此时发送登录请求。

==> 请求会进入到核心控制器,进入核心控制器之前先经过一系列的过滤器进行过滤。

==> 核心控制器会通过Action代理对象读取请求(读取struts.xml文件)。

==> 进入Action之前会经过一系列的拦截器。

==> 进入Action控制器执行后,会根据返回的结果字符串选择相应的视图,登录成功,去到首页,登录失败,回到登录页面。

1.2、核心接口和类

在这里插入图片描述
(1)ActionMapper接口

此接口根据请求的URI查找是否存在对应的Action调用。org.apache.struts2.dispatcher.mapper.ActionMapper类源码如下:

public interface ActionMapper {

    /**
     * Expose the ActionMapping for the current request
     *
     * @param request The servlet request
     * @param configManager The current configuration manager
     * @return The appropriate action mapping or null if mapping cannot be determined
     */
    ActionMapping getMapping(HttpServletRequest request, ConfigurationManager configManager);

    /**
     * Expose the ActionMapping for the specified action name
     *
     * @param actionName The name of the action that may have other information embedded in it
     * @return The appropriate action mapping
     * @since 2.1.1
     */
    ActionMapping getMappingFromActionName(String actionName);

    /**
     * Convert an ActionMapping into a URI string
     *
     * @param mapping The action mapping
     * @return The URI string that represents this mapping
     */
    String getUriFromActionMapping(ActionMapping mapping);
}

(2)ActionMapping类

此类保存调用Action的映射信息,比如Action的name、namespace等。org.apache.struts2.dispatcher.mapper.ActionMapping类源码如下:

public class ActionMapping {

    private String name;
    private String namespace;
    private String method;
    private String extension;
    private Map<String, Object> params;
    private Result result;

    /**
     * Constructs an ActionMapping
     */
    public ActionMapping() {
        params = new HashMap<>();
    }

    /**
     * Constructs an ActionMapping with a default result
     *
     * @param result The default result
     */
    public ActionMapping(Result result) {
        this.result = result;
    }

    /**
     * Constructs an ActionMapping with its values
     *
     * @param name The action name
     * @param namespace The action namespace
     * @param method The method
     * @param params The extra parameters
     */
    public ActionMapping(String name, String namespace, String method, Map<String, Object> params) {
        this.name = name;
        this.namespace = namespace;
        this.method = method;
        this.params = params;
    }

    /**
     * @return The action name
     */
    public String getName() {
        return name;
    }

    /**
     * @return The action namespace
     */
    public String getNamespace() {
        return namespace;
    }

    /**
     * @return The extra parameters
     */
    public Map<String, Object> getParams() {
        return params;
    }

    /**
     * @return The method
     */
    public String getMethod() {
        if (null != method && "".equals(method)) {
            return null;
        } else {
            return method;
        }
    }

    /**
     * @return The default result
     */
    public Result getResult() {
        return result;
    }
    
    /**
     * @return The extension used during this request
     */
    public String getExtension() {
        return extension;
    }

    /**
     * @param result The result
     */
    public void setResult(Result result) {
        this.result = result;
    }

    /**
     * @param name The action name
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * @param namespace The action namespace
     */
    public void setNamespace(String namespace) {
        this.namespace = namespace;
    }

    /**
     * @param method The method name to call on the action
     */
    public void setMethod(String method) {
        this.method = method;
    }

    /**
     * @param params The extra parameters for this mapping
     */
    public void setParams(Map<String, Object> params) {
        this.params = params;
    }
    
    /**
     * @param extension The extension used in the request
     */
    public void setExtension(String extension) {
        this.extension = extension;
    }

    @Override
    public String toString() {
        return "ActionMapping{" +
                "name='" + name + '\'' +
                ", namespace='" + namespace + '\'' +
                ", method='" + method + '\'' +
                ", extension='" + extension + '\'' +
                ", params=" + params +
                ", result=" + (result != null ? result.getClass().getName() : "null") +
                '}';
    }

}

这个类就是一个简单的实体类,保存Action的各种属性信息。

(3)ActionProxy接口

这是一个代理接口,在真正的XWork和Action之间充当代理。com.opensymphony.xwork2.ActionProxy类源码如下:

public interface ActionProxy {

    /**
     * Gets the Action instance for this Proxy.
     *
     * @return the Action instance
     */
    Object getAction();

    /**
     * Gets the alias name this ActionProxy is mapped to.
     *
     * @return the alias name
     */
    String getActionName();

    /**
     * Gets the ActionConfig this ActionProxy is built from.
     *
     * @return the ActionConfig
     */
    ActionConfig getConfig();

    /**
     * Sets whether this ActionProxy should also execute the Result after executing the Action.
     *
     * @param executeResult <tt>true</tt> to also execute the Result.
     */
    void setExecuteResult(boolean executeResult);

    /**
     * Gets the status of whether the ActionProxy is set to execute the Result after the Action is executed.
     *
     * @return the status
     */
    boolean getExecuteResult();

    /**
     * Gets the ActionInvocation associated with this ActionProxy.
     *
     * @return the ActionInvocation
     */
    ActionInvocation getInvocation();

    /**
     * Gets the namespace the ActionConfig for this ActionProxy is mapped to.
     *
     * @return the namespace
     */
    String getNamespace();

    /**
     * Execute this ActionProxy. This will set the ActionContext from the ActionInvocation into the ActionContext
     * ThreadLocal before invoking the ActionInvocation, then set the old ActionContext back into the ThreadLocal.
     *
     * @return the result code returned from executing the ActionInvocation
     * @throws Exception can be thrown.
     * @see ActionInvocation
     */
    String execute() throws Exception;

    /**
     * Gets the method name to execute, or <tt>null</tt> if no method has been specified (meaning <code>execute</code> will be invoked).
     *
     * @return the method to execute
     */
    String getMethod();

    /**
     * Gets status of the method value's initialization.
     *
     * @return true if the method returned by getMethod() is not a default initializer value.
     */
    boolean isMethodSpecified();
    
}

(4)ActionInvocation接口

此接口的作用是表示Action的执行状态,保存拦截器、Action的实例。com.opensymphony.xwork2.ActionInvocation类源码如下:

public interface ActionInvocation {

    /**
     * Get the Action associated with this ActionInvocation.
     *
     * @return the Action
     */
    Object getAction();

    /**
     * Gets whether this ActionInvocation has executed before.
     * This will be set after the Action and the Result have executed.
     *
     * @return <tt>true</tt> if this ActionInvocation has executed before.
     */
    boolean isExecuted();

    /**
     * Gets the ActionContext associated with this ActionInvocation. The ActionProxy is
     * responsible for setting this ActionContext onto the ThreadLocal before invoking
     * the ActionInvocation and resetting the old ActionContext afterwards.
     *
     * @return the ActionContext.
     */
    ActionContext getInvocationContext();

    /**
     * Get the ActionProxy holding this ActionInvocation.
     *
     * @return the ActionProxy.
     */
    ActionProxy getProxy();

    /**
     * If the ActionInvocation has been executed before and the Result is an instance of {@link ActionChainResult}, this method
     * will walk down the chain of <code>ActionChainResult</code>s until it finds a non-chain result, which will be returned. If the
     * ActionInvocation's result has not been executed before, the Result instance will be created and populated with
     * the result params.
     *
     * @return the result.
     * @throws Exception can be thrown.
     */
    Result getResult() throws Exception;

    /**
     * Gets the result code returned from this ActionInvocation.
     *
     * @return the result code
     */
    String getResultCode();

    /**
     * Sets the result code, possibly overriding the one returned by the
     * action.
     *
     * <p>
     * The "intended" purpose of this method is to allow PreResultListeners to
     * override the result code returned by the Action.
     * </p>
     *
     * <p>
     * If this method is used before the Action executes, the Action's returned
     * result code will override what was set. However the Action could (if
     * specifically coded to do so) inspect the ActionInvocation to see that
     * someone "upstream" (e.g. an Interceptor) had suggested a value as the
     * result, and it could therefore return the same value itself.
     * </p>
     *
     * <p>
     * If this method is called between the Action execution and the Result
     * execution, then the value set here will override the result code the
     * action had returned.  Creating an Interceptor that implements
     * {@link PreResultListener} will give you this opportunity.
     * </p>
     *
     * <p>
     * If this method is called after the Result has been executed, it will
     * have the effect of raising an IllegalStateException.
     * </p>
     *
     * @param resultCode  the result code.
     * @throws IllegalStateException if called after the Result has been executed.
     * @see #isExecuted()
     */
    void setResultCode(String resultCode);

    /**
     * Gets the ValueStack associated with this ActionInvocation.
     *
     * @return the ValueStack
     */
    ValueStack getStack();

    /**
     * Register a {@link PreResultListener} to be notified after the Action is executed and
     * before the Result is executed.
     *
     * <p>
     * The ActionInvocation implementation must guarantee that listeners will be called in
     * the order in which they are registered.
     * </p>
     *
     * <p>
     * Listener registration and execution does not need to be thread-safe.
     * </p>
     *
     * @param listener the listener to add.
     */
    void addPreResultListener(PreResultListener listener);

    /**
     * Invokes the next step in processing this ActionInvocation.
     *
     * <p>
     * If there are more Interceptors, this will call the next one. If Interceptors choose not to short-circuit
     * ActionInvocation processing and return their own return code, they will call invoke() to allow the next Interceptor
     * to execute. If there are no more Interceptors to be applied, the Action is executed.
     * If the {@link ActionProxy#getExecuteResult()} method returns <tt>true</tt>, the Result is also executed.
     * </p>
     *
     * @throws Exception can be thrown.
     * @return the return code.
     */
    String invoke() throws Exception;

    /**
     * Invokes only the Action (not Interceptors or Results).
     *
     * <p>
     * This is useful in rare situations where advanced usage with the interceptor/action/result workflow is
     * being manipulated for certain functionality.
     * </p>
     *
     * @return the return code.
     * @throws Exception can be thrown.
     */
    String invokeActionOnly() throws Exception;

    /**
     * Sets the action event listener to respond to key action events.
     *
     * @param listener the listener.
     */
    void setActionEventListener(ActionEventListener listener);

    void init(ActionProxy proxy) ;

}

(5) Interceptor接口

此接口是在请求处理之前或处理之后执行的组件。com.opensymphony.xwork2.interceptor.Interceptor类源码如下:

public interface Interceptor extends Serializable {

    /**
     * Called to let an interceptor clean up any resources it has allocated.
     */
    void destroy();

    /**
     * Called after an interceptor is created, but before any requests are processed using
     * {@link #intercept(com.opensymphony.xwork2.ActionInvocation) intercept} , giving
     * the Interceptor a chance to initialize any needed resources.
     */
    void init();

    /**
     * Allows the Interceptor to do some processing on the request before and/or after the rest of the processing of the
     * request by the {@link ActionInvocation} or to short-circuit the processing and just return a String return code.
     *
     * @param invocation the action invocation
     * @return the return code, either returned from {@link ActionInvocation#invoke()}, or from the interceptor itself.
     * @throws Exception any system-level error, as defined in {@link com.opensymphony.xwork2.Action#execute()}.
     */
    String intercept(ActionInvocation invocation) throws Exception;

}

1.3、流程简图

在这里插入图片描述

Struts2从请求到响应的基本流程如上图所示:

  • 请求首先经过Struts2的核心控制器。
  • 然后经过一系列的拦截器。
  • 经过拦截器之后,到达Action,由Actioh处理,返回Result视图。
  • 在响应之前,再次经过拦截器,注意,和请求进入时经过的拦截器顺序相反。比如进入时经过的是拦截器1 -> 拦截器2 -> 拦截器3,那么响应之前经过的顺序就是拦截器3 -> 拦截器2 -> 拦截器1。
  • 最后根据Result返回结果,响应视图,跳转页面。

2、Struts2拦截器

2.1、使用拦截器的目的

早期MVC框架将一些通用操作的硬编码放在核心控制器中,致使框架灵活性不足,可扩展降低。
Struts2将核心功能放到多个拦截器中实现,拦截器可自由选择和组合,增强了灵活性,有利于系统的解耦。

2.2、拦截器的简介

Struts2大多数核心功能都是通过拦截器实现的,每个拦截器都会完成某项特定的功能。

拦截器方法在Action执行之前和之后(顺序相反)执行。

拦截器栈:

==> 从结构上看,拦截器栈相当于多个拦截器的组合。
==> 在功能上看,拦截器栈也是拦截器。

拦截器和过滤器的原理很相似。

2.3、拦截器的工作原理

在这里插入图片描述

2.4、拦截器的使用

2.4.1、创建自定义拦截器

自定义拦截器可以通过继承AbstractInterceptpr或MethodFilterInterceptor(可进行方法级别的拦截)。如下:

/**   
 * @ClassName:  TestInterceptor   
 * @Description: 自定义拦截器
 * @author: yanchengzhi
 * @date:   2023年1月18日 下午3:07:10      
 * @Copyright:  
 */
public class TestInterceptor extends AbstractInterceptor {

	@Override
	public String intercept(ActionInvocation invocation) throws Exception {
		System.out.println("进入第一个拦截器!");
		// 放行
		String result = invocation.invoke();
		System.out.println("退出第一个拦截器!");
		return result;
	}

}

2.4.2、struts.xml中定义和配置拦截器

在核心配置文件struts.xml的package标签内进行配置,如下:

    <package name="test1" extends="default">
        <!-- 定义拦截器 -->
        <interceptors>
            <interceptor name="test1" class="com.ycz.web.interceptors.TestInterceptor" />
        </interceptors>

        <action name="hello" class="com.ycz.web.HelloAction">
            <result>/success.jsp</result>
            <!-- 引用拦截器 -->
            <interceptor-ref name="test1" />
            <!-- 引用默认拦截器 -->
            <interceptor-ref name="defaultStack" />
        </action>
    </package>

注意,拦截器要先定义后引用。

2.4.3、Struts2默认拦截器

在这里插入图片描述

在struts2中有一些已经定义好的默认拦截器,源码的struts-default.xml中有配置,如下:

            <interceptor-stack name="defaultStack">
                <interceptor-ref name="exception"/>
                <interceptor-ref name="alias"/>
                <interceptor-ref name="servletConfig"/>
                <interceptor-ref name="i18n"/>
                <interceptor-ref name="prepare"/>
                <interceptor-ref name="chain"/>
                <interceptor-ref name="scopedModelDriven"/>
                <interceptor-ref name="modelDriven"/>
                <interceptor-ref name="fileUpload"/>
                <interceptor-ref name="checkbox"/>
                <interceptor-ref name="datetime"/>
                <interceptor-ref name="multiselect"/>
                <interceptor-ref name="staticParams"/>
                <interceptor-ref name="actionMappingParams"/>
                <interceptor-ref name="params"/>
                <interceptor-ref name="conversionError"/>
                <interceptor-ref name="validation">
                    <param name="excludeMethods">input,back,cancel,browse</param>
                </interceptor-ref>
                <interceptor-ref name="workflow">
                    <param name="excludeMethods">input,back,cancel,browse</param>
                </interceptor-ref>
                <interceptor-ref name="debugging"/>
            </interceptor-stack>

注意:Struts2的所有功能都包含在默认的defaultStack中,如果引用了自定义的拦截器,就必须引用默认的defaultStack拦截器,否则Struts2的所有功能都会失效。

2.4.4、拦截器栈

拦截器栈的作用是组合多个拦截器,还是先定义拦截器,再配置拦截器栈,最后再引用拦截器栈即可。

        <interceptors>
            <!-- 定义拦截器 -->
            <interceptor name="test1" class="com.ycz.web.interceptors.TestInterceptor" />

            <!-- 配置拦截器栈,可自由组合多个拦截器 -->
            <interceptor-stack name="myStack">
                <interceptor-ref name="test1" />
                <interceptor-ref name="defaultStack" />
            </interceptor-stack>
        </interceptors>

在这里插入图片描述

2.5、例子

下面定义一个拦截器,对请求进行拦截。

(1)创建拦截器

创建一个拦截器,继承MethodFilterInterceptor,对某些方法进行拦截,而某些方法不需要拦截。

public class LoginInterceptor extends MethodFilterInterceptor {

	private static final long serialVersionUID = 1L;

	@Override
	protected String doIntercept(ActionInvocation invocation) throws Exception {
		System.out.println("进入拦截器!");
		HttpSession session = ServletActionContext.getRequest().getSession();
		if(session.getAttribute("loginUser") == null) {
			return Action.LOGIN;
		}
		System.out.println("用户【" + session.getAttribute("loginUser") + "】已登录!");
		return invocation.invoke();
	}

}

(2)创建Action控制器

创建Login2Action控制器类,继承ActionSupport,如下:

public class Login2Action extends ActionSupport {
	
	private static final long serialVersionUID = 1L;

	private String username;
	
	private String password;
	
	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public String loginRequest() {
		System.out.println(username + "===>" + password);
		if(username.equals("admin") && password.equals("admin123456")) {
			ServletActionContext.getRequest().getSession().setAttribute("loginUser", username);
			return SUCCESS;
		}
		return LOGIN;
	}
	
	public String registerRequest() {
		System.out.println("用户注册");
		return SUCCESS;
	}
	
	public String updateRequest() {
		System.out.println("用户更新");
		return SUCCESS;
	}
	
	public String deleteRequest() {
		System.out.println("用户删除");
		return SUCCESS;
	}

}

(3)struts.xml配置

        <struts>
             <constant name="struts.enable.DynamicMethodInvocation" value="true" />
             <package name="default" extends="struts-default" namespace="/user">
                 <!-- 拦截器配置 -->
                <interceptors>
                    <!-- 登录拦截器 -->
                    <interceptor name="myLoginInterceptor" class="com.ycz.struts01.interceptor.LoginInterceptor"  />
                    <!-- 拦截器栈 -->
                    <interceptor-stack name="myLoginInterceptorStack">
                          <interceptor-ref name="defaultStack" />
                          <interceptor-ref name="myLoginInterceptor">
                               <!-- 设置需要拦截的方法 -->
                               <param name="includeMethods">
                                  register*,update*,delete*
                               </param>
                               <!-- 设置不需拦截的方法 -->
                               <param name="excludeMethods">login*</param>
                          </interceptor-ref>
                    </interceptor-stack>
                </interceptors>
                <global-allowed-methods>regex:.*</global-allowed-methods>
                 <action name="user" class="com.ycz.struts01.action.Login2Action" >
                      <result>/success.jsp</result>
                      <result name="login">/login2.jsp</result>
                      <interceptor-ref name="myLoginInterceptorStack" />
                 </action>
       
             </package>
             
        </struts>

注意:如果配置了拦截器栈来组合多个拦截器,那么拦截器栈一定要包含默认的defaultStack拦截器,如果不包含,那么struts2的所有默认拦截配置都会失效(比如无法接收参数)。

(4)页面

login2.jsp页面:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
     <form action="user/user!loginRequest.action" method="post">
          <div>
             <label>用户名:</label>
             <input type="text" name="username" />
          </div>
          <div>
             <label>密码:</label>
             <input type="password" name="password" />
          </div>
          <div>
             <input type="submit" value="提交" />
          </div>
     </form>
</body>
</html>

success.jsp页面:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
    <%@ taglib prefix="s" uri="/struts-tags" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>主页面</title>
</head>
<body>
   <h1>当前用户:【${sessionScope.loginUser }】</h1>
   <a href="user/user!registerRequest.action">注册请求</a><br/>
   <a href="user/user!updateRequest.action">更新请求</a><br/>
   <a href="user/user!deleteRequest.action">删除请求</a><br/>
</body>
</html>

(5)测试

启动项目,访问http://localhost:8081/struts01/login2.jsp:

在这里插入图片描述
填写错误的用户名密码,提交,控制台打印:

在这里插入图片描述
可以看到,控制器没有对loginRequest方法进行拦截,因为这里的配置:

在这里插入图片描述
然后输入正确的用户名密码进行登录,页面跳转:

在这里插入图片描述
控制台打印:

在这里插入图片描述
因为还是走的loginRequest方法,所以拦截器没有进行拦截。几个链接:
在这里插入图片描述
请求的这几个方法,刚好配置了拦截器进行拦截:

在这里插入图片描述
在这里插入图片描述
按照拦截器的逻辑,用户未登录直接跳回登录页,登录了打印信息。依次点击页面的三个链接:
在这里插入图片描述
控制台打印:

在这里插入图片描述
可以看到,拦截器对这三个方法拦截成功。

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

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

相关文章

Leetcode.2319 判断矩阵是否是一个 X 矩阵

题目链接 Leetcode.2319 判断矩阵是否是一个 X 矩阵 Rating : 1201 题目描述 如果一个正方形矩阵满足下述 全部 条件&#xff0c;则称之为一个 X矩阵 &#xff1a; 矩阵对角线上的所有元素都 不是 0 矩阵中所有其他元素都是 0 给你一个大小为 n x n的二维整数数组 grid&#…

ElasticSearch - 旅游酒店案例es功能实现

目录 案例 搜索与分页功能 条件过滤功能 附近的酒店功能 广告置顶功能 HotelService(es操作)总览 案例 搜索与分页功能 案例需求&#xff1a;实现旅游的酒店搜索功能&#xff0c;完成关键字搜索和分页实现步骤如下&#xff1a;1.定义实体类&#xff0c;接收前端请求实体…

微信小程序用vant自定义tabbar页面并跳转相应页面

0.前置安装 步骤一 安装 vant 组件库 npm i vant/weapp -S --production下载完后要npm构建才能使用 步骤二 修改 app.json 将 app.json 中的 "style": "v2" 去除&#xff0c;小程序的新版基础组件强行加上了许多样式&#xff0c;难以覆盖&#xff0c;不…

分布式定时任务框架选型

目录 1. 前言 2. 定时任务框架 3. 分布式任务调度系统对比 4. 和quartz框架对比 5. 综合对比 6. 总结和结论 7. 附定时任务的其他方案 1. 前言 我们先思考下面几个业务场景的解决方案: 支付系统每天凌晨1点跑批&#xff0c;进行一天清算&#xff0c;每月1号进行上个月清…

【算法】快速排序算法原理及实现

1.什么是快速排序算法 快速排序是对冒泡排序的一种改良版&#xff0c;通过一趟排序&#xff0c;把要排序的序列分割成两个部分&#xff0c;一部分的所有数据要比另一部分的数据都小&#xff0c;然后再根据这两部分的数据来进行快速排序。以此来达到整一个数据都变成了有序序列…

AI算法创新赛-人车目标检测竞赛总结01

AI0000020摘要:人车目标检测竞赛主要考察目标检测算法与 TPU 部署推理&#xff0c;主要考察算法选型与调 优&#xff0c;面向算能 TPU 迁移部署与推理加速两项能力;主要考核目标是算法效果(mAP)与推 理性能(单张图片推理时间)。针对这些要求&#xff0c;笔者从算法选型&#xf…

【实际开发11】- 统计 / 科学计算 - 1

目录 1. sql 统计返回值为 null 时 , 赋值 为 : 0 ( return UI ) 1. 手动 null 判断 , 进行 “0” 赋值 2. XxxxVO 展示对象 , 初始化时 , 赋值默认值 ( 待优化 ) 2. 统计异常 1. 注意中间表数据的维护 ( 同步删除 / 避免手动删数据 ) 3. 精度损失 1. Java 类型 float、…

.NET(C#、VB)APP开发——Smobiler平台控件介绍:LiveStream和LiveStreamPlayer

本文简述如何在Smobiler中使用LiveStream和LiveStreamPlayer。 LiveStream 直播推送插件 Step 1. 新建一个SmobilerForm窗体&#xff0c;并在窗体中加入LiveStream和Button&#xff0c;布局如下 选中LisvStream&#xff0c;在设计器中设置Url&#xff08;需要事先准备一个视频…

【面试原型链】前端面试那些事(1)之原型链详解

【写在前面】辞旧迎新的春季佳节&#xff0c;在这里博主先祝各位看官新的一年赚钱多多&#xff0c;知识满满&#xff0c;年后谈到面试&#xff0c; 好多人在面试的时候就倒在原型链知识点上面&#xff0c;主要原因还是基本功不够扎实&#xff0c;针对以前的知识我也计划在2023年…

C语言小题,通过指向结构体变量的指针变量输出结构体变量中成员的信息。(指针结构体变量的指针)

前言&#xff1a; 此篇是针对 指针结构体变量的指针 方面的练习。 解题思路&#xff1a; 在已有的基础上&#xff0c;本题要解决两个问题&#xff1a; &#xff08;1&#xff09;怎样对结构体变量成员赋值&#xff1b; &#xff08;2&#xff09;怎样通过指向结构体变量的指针…

天云数据:Hubble数据库系统自主研发率99.62%,是真正的信创数据库

软件是新一代信息技术的灵魂&#xff0c;是数字经济发展的基础&#xff0c;是制造强国、网络强国、数字中国建设的关键支撑。2021年&#xff0c;工信部印发的《“十四五”软件和信息技术服务业发展规划》明确指出&#xff0c;要聚力攻坚基础软件&#xff0c;关键基础软件补短板…

Javascript基础复盘5

内置对象 值属性 这些全局属性返回一个简单值&#xff0c;这些值没有自己的属性和方法。 InfinityNaNundefinedglobalThis函数属性 全局函数可以直接调用&#xff0c;不需要在调用时指定所属对象&#xff0c;执行结束后会将结果直接返回给调用者。 eval()uneval()isFinite()isN…

Q-Learning以及.NET环境下的实现

Q-Learning以及.NET环境下的实现写在前面机器学习Q-Learning环境准备试题准备解题过程写在结尾写在前面 看过我的文章的朋友应该都知道&#xff0c;我之前一直在研究视觉相关的知识&#xff0c;也看了一些卷积神经网络&#xff08;CNN&#xff09;&#xff0c;深度学习相关的文…

强化学习之:价值学习Value-Based Learning

文章目录参考内容动作价值函数&#xff08;Action-value Function&#xff09;深度强化学习&#xff08;DQN&#xff09;学习目标&#xff08;Goal&#xff09;如何获得尽可能好的 Q∗(st,a)→Q^{*}(s_t, a) \rightarrowQ∗(st​,a)→ 用神经网络通过学习获得时间差分算法&…

cocos creater 3.x 开发笔记(踩坑总结)

1、cocos creater 3.x 花屏闪屏黑屏 1.1 花屏 排序是一个很简单的功能&#xff0c;但是最终的呈现却是根据不同平台提供的渲染能力来的。因此&#xff0c;在这里说明一下&#xff0c;如果遇到了 UI 渲染出错&#xff0c;花屏&#xff0c;闪屏等现象&#xff0c;首先要检查的就…

【安装合集】Mysql8.0安装 2023年1月31日 22点15分

1.鼠标右击【Mysql8.0】压缩包选择【解压到Mysql8.0】。 2. 鼠标右击【mysql-installer-community-8.0.17.0】选择【安装】 3. 勾选【I accept the license terms】然后点击【Next】。 4. 选择【Custom】然后点击【Next】。 5. 双击【MySQL Servers】 双击【MySQL Server】&am…

数据指标体系的建设思考(四)

这一篇主要介绍对数据指标体系的价值、数据指标管理平台的理解及数据分析的趋势解读。 一、数据指标体系价值 关于数据指标体系的价值&#xff0c;我想大多数从事数据工作的人员都可以感受得到&#xff0c;毕竟数据指标的输出可以通过可视化的方式&#xff08;如大屏、驾驶舱…

Linux 中去除 vi/vim 和 git diff 中的 ^M 问题解决办法

去除 vi/vim 和 git diff 中的 ^M 问题解决办法问题现象初步分析进一步查看问题解决Source Insightdos2unixNodpadVimsed 命令综上Reference问题现象 git diff 时发现下面的情况&#xff0c;新修改的代码之处都是携带 ^M 字符&#xff0c; 初步分析 肯定是因为 Windows 和 …

推荐5款常用的有限元分析CAE软件

正如我们之前谈到的&#xff0c;计算机辅助软件有助于进行有限元分析。但是我们如何识别好的 CAE 软件呢&#xff1f;CAE 软件必须满足以下要求才能被纳入其类别使用户能够通过图形用户界面 (GUI) 创建模拟允许在模拟中测试组件&#xff0c;同时具有可自定义的环境变量协助优化…

JAVA队列-接口

前言 说到队列,大家都不陌生,很多场景都需要使用到队列,今天我们一起学习JDK提供的队列源码 类图 Queue接口的实现类有很多 从中,我们看到几个熟悉的,BlockingQueue 阻塞队列、Deque 双端队列 Queue 官方介绍: A collection designed for holding elements prior to proce…