`
Qieqie
  • 浏览: 341988 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

Hessian,rcp,有状态,模拟会话,ThreadLocal,AOP

阅读更多
不知道如何给本帖子取名,所以在标题出仅仅列出一些关键字。


本帖是工作成果之总结发贴,又由于太长,故有关心hessian/burlap/RCP如何在客户端和服务端之间默认传送参数,使服务器端的对象能够使用ThreadLocal获得当前远程请求者信息的同学 可以看看这个帖子,其它同学可以忽略之  否则看这这么长的贴可能会很受罪

背景
在远程调用框架方面,Spring现在能够良好集成Hessian/Burlap之类基于Http的RCP。 构建这样的程序基本步骤是这样的:
1,创建并配置POJO形式的服务对象,比如UserBo;
2、远程调用暴露器,比如Spring提供的Hessian暴露器,使成为web服务;
3、客户端(e.g.Swing-based)通过proxy,按照UserBo的接口调用远程服务

问题
区别于浏览器通过http访问Web服务器,浏览器能够支持它和服务器端cookie传送,
使本没有状态的http协议在web上能够提供有状态的服务,web容器因此可以通过标准的HttpSession保存登录信息等。

而这是一般使用Hessian之类的RCP难以做到的,如何模拟浏览器传送"cookie"成为头痛的问题。我一直为这件事烦恼着,做了这几个试验:
1、Hessian客户端能够保持服务器送过来的Cookie吗?   不能。试验过程如下:
1)做一个Filter过滤器,过滤Hessian远程调用
2)获取request.getSession(),打印sessionId
通过打印,看出每一次调用打印的sessionId都不一样,所以试图直接使用HttpSession保持会话是不行的。

现在已经没办法通过HttpSession机制处理这个问题,那
1、如何确定每次从swing到server的hessian调用是登录后的调用,而不会被人模拟调用?
2、我如何知道每次调用的调用者是谁?

头脑风暴
头脑中一下子蹦出来的是:每个调用方法都加一个userId参数。

“搞定!”but极其ugly,想想,一般情况下,我不希望Bo提供的每一个方法都要求加一个UserId,我不会。
如果想要知道当前是由谁调用这个Bo类,在普通的web应用上,我采用的是Filter+ThreadLocal来做的,
这样只需在Bo方法里面调用提供ThreadLocal服务的全局共享对象来获取当前的请求者。

我不会在Bo中加入userId参数的,除非万不得已。。。继续苦思冥想....

是否能够改变Hessian客户端代理,使其能够读取http头信息,并在每次发送新请求时再把读取的cookie送到服务器?我想这是个不错的方案,但汗了一下,同上,也只要在“需求极其有必要+没有其它办法”条件下才去改变别人的底层结构。暂行搁置此方案。

有了,借助了“网络协议栈”提供的编程思想+AOP,我想到了一个方法,并在进行了试验性实践,证明可行了
因为可能也有人需要:《如何在hessian的环境下模拟session(会话)》, 或者可以用来参考拓展一下编程思路,所以我写这个总结。。。花费了我近2个小时,快晕死了


终极解决-思路
1、协议栈思想:
协议栈告诉我们下层协议总是“偷偷”的在上层协议内容之外再加上一些额外的,和本层协议有关的内容,发送到网络另外一端,同时另外那一端的对等协议,接收传输内容时,会剥离刚才加入的额外信息进行控制,并把剥离后的协议内容往上一层推。。。。

2、AOP理论:
拦截器,就像土匪,在你行走的路上,硬要对你进行盘问,满意则放人通过,不满意可以把你潜回;它可以偷袭你一些数据,也可能悄悄地加入他想要的行为、数据

3、协议栈思想 + AOP
客户端调用某个Bo的方法时,配置代理bean给他,这个代理bean同时也是拦截器,客户端调用Bo的每个方法都会被拦截,去调用一个底层接口(Delegate)。这个底层接口,能把你要调用的Bo名称,方法名,参数记起来,并加上每次你都需要传给服务器的参数传送到服务器。同时在服务器端,有一个这个底层接口个对应的服务对象(由DelegateImpl实现),该实现会把拦截器刚才记住的这些信息找出来:
取回拦截器刚才悄悄加入的信息(Attachments)记录在一个和ThreadLocal相关的类中(由Current实现);
取回你要调的Bo名称,从服务器applicationContext中找到这个对象
通过方法名和参数找到最终要调用的Method对象,最终调用method.invoke,实现对服务端Bo的调用。

分享到:
评论
17 楼 歆渊 2007-08-07  
gwbasic 写道
Java 6.0HttpUrlConnection已经支持Cookie了

哦, 6.0 已经归入官方类库了.

我原来是把 JDK 源码中 plugin 部分的 MemoryCookieHandler rip 过来用的, 附件为代码, 6.0 以前的 JVM 还可以用.
16 楼 gwbasic 2007-06-13  
Java 6.0HttpUrlConnection已经支持Cookie了

	public static void main(String[] args) {
		CookieHandler.setDefault(new CookieManager(null, CookiePolicy.ACCEPT_ALL));
		HessianProxyFactory factory = new HessianProxyFactory();
		try {
			TestService testService = (TestService) factory.create(TestService.class,
			        "http://127.0.0.1:8080/hessian/remoting/TestService");
			System.out.println(testService.getSessionId("您好."));
			System.out.println(testService.getSessionId("您好."));

			testService = (TestService) factory.create(TestService.class,
			        "http://127.0.0.1:8080/hessian/remoting/TestService");
			System.out.println(testService.getSessionId("您好."));
			System.out.println(testService.getSessionId("您好."));
		} catch (MalformedURLException e) {
			e.printStackTrace();
		}
	}
15 楼 dovecat 2007-05-24  
好长...
14 楼 Qieqie 2007-05-24  
good!

你的代码给了另外一个不错的思路了,关键是你提供的下面这个代码,我可以进行扩展,动态塞入一些附带想要传给服务器的数据,然后做Filter从Http Header取出来放到ThreadLocal
(我还是免不了要N些封装类,使这些代码对编程透明,以及支持Spring配置。。。)

考虑一下,是否可以扩展Hessian使能够读取服务器传过来的HttpHeader数据,从而把session的cookie读出来? 如果可以的话,那HttpSession就可以使用了!

补充:很高兴看到readonly的代码!

public class IdentityHessianProxyFactory extends HessianProxyFactory {
    public static final String IDENTITY_KEY = "_hessian_client_";

    private String clientId;

    public IdentityHessianProxyFactory(String clientId) {
        super();
        this.clientId = clientId;
    }

    protected URLConnection openConnection(URL url) throws IOException {
        URLConnection conn = super.openConnection(url);
        conn.setRequestProperty(IDENTITY_KEY, clientId);
        return conn;
    }
}

13 楼 Readonly 2007-05-24  
唉,咋就不理解偶的意思呢?不多说了,看附件的代码,附件没有考虑多线程问题,你用filter取代掉BasicServiceImpl里面service这一块代码,把取得的用户标识放到ThreadLocal就可以了。5行代码就可以搞定的事情,还弄这么麻烦....
12 楼 Qieqie 2007-05-24  
大部分没必要,有时有必要。
其实在我的帖子里面,倒没有一定是statefull,只是记录信息到ThreadLocal(即Current类中)。也就是我最想解决的是能够支持在Bo里面通过ThreadLocal的机制知道当前的请求者,这有可能有好处(有时候这种好处可能不小,比如控制安全,判断权限,记录访问日志等等)
11 楼 max.h.chen 2007-05-24  
为什么需要stateful hessian?RPC要的就是stateless,难道hessian客户端连自己的状态都管理不了吗?不会瘦到这种程度吧!
10 楼 Qieqie 2007-05-24  
HttpSession session = req.getSession(false);

表示如果当前有Session则返回,没有的话就返回null,
每次都返回null,做不到Statefull.


HttpSession session = req.getSession(); 等价于HttpSession session = req.getSession(true);
如果当前会话已经存在,则返回该会话,没有的话创建一个-->这是我们需要的恶
9 楼 Readonly 2007-05-24  
剑精or风怒了,编辑掉
8 楼 Readonly 2007-05-24  
Qieqie 写道
是因为cookie没办法被hessian客户读取记录导致的http session没办法使用。
因为创建http session对hessian没有意义,也就不需要去一直获取,也就没有因为session导致大负荷量负载下Session狂暴的问题

你也试验下告诉下结果,免得就我一个环境实验,可能存在偏差


你的理解有错误,默认的Hessian Servlet实现是不创建session,而你的测试代码里面为什么会打出不同的session id,是因为这句话:
HttpSession session = req.getSession();
修改成
HttpSession session = req.getSession(false);
你就会发现问题的根源
7 楼 Qieqie 2007-05-24  
是因为cookie没办法被hessian客户读取记录导致的http session没办法使用。
因为创建http session对hessian没有意义,也就不需要去一直获取,也就没有因为session导致大负荷量负载下Session狂暴的问题

你也试验下告诉下结果,免得就我一个环境实验,可能存在偏差

<?xml version="1.0" encoding="UTF-8"?>
<web-app>
	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>
			/WEB-INF/applicationContext*.xml
		</param-value>
	</context-param>
	<listener>
		<listener-class>
			org.springframework.web.context.ContextLoaderListener
		</listener-class>
	</listener>
	<servlet>
		<servlet-name>remoting</servlet-name>
		<servlet-class>
			org.springframework.web.servlet.DispatcherServlet
		</servlet-class>
		<load-on-startup />
	</servlet>

	<servlet-mapping>
		<servlet-name>remoting</servlet-name>
		<url-pattern>/remoting/*</url-pattern>
	</servlet-mapping>
	
	
	<filter>
		<filter-name>TestFilter</filter-name>
		<filter-class>
			com.xxx.TestFilter
		</filter-class>
	</filter>
	<filter-mapping>
		<filter-name>TestFilter</filter-name>
		<url-pattern>/remoting/*</url-pattern>
	</filter-mapping>
	
</web-app>
6 楼 Readonly 2007-05-24  
你的web.xml不完整,附上完整的看看

Hessian不可能愚蠢到每次请求都创建一个新的session,这样在高压力负载下的生产环境,application server马上就会被几十万个active session弄趴下了。
5 楼 Qieqie 2007-05-24  
Readonly 写道
Qieqie 写道

2)获取request.getSession(),打印sessionId
通过打印,看出每一次调用打印的sessionId都不一样,所以试图直接使用HttpSession保持会话是不行的。

你肯定实验错了,后面的一堆烦琐的解决方案先不看了,把你的测试代码放出来。
用Hessian解决Stateful的问题很简单,多加一个Filter,把session里面的用户标识读到就可以了。


你做过这个试验?我把我的试验代码和结果显示在下面了,你也列来看看,如果可以的话,那世界真的很美丽了(不过这是不可能的)
如果不是的话,所谓的繁琐,难度较大的也都在封转底层代码中了,外面的编程可简单多了(=Filter+ThreadLocal的代码量)

web.xml配置片段
	<filter>
		<filter-name>TestFilter</filter-name>
		<filter-class>
			com.xxx.TestFilter
		</filter-class>
	</filter>
	<filter-mapping>
		<filter-name>TestFilter</filter-name>
		<url-pattern>/remoting/*</url-pattern>
	</filter-mapping>



Filter Session id打印代码
public class TestFilter implements Filter {

	public void destroy() {
		// TODO Auto-generated method stub

	}

	public void doFilter(ServletRequest arg0, ServletResponse arg1,
			FilterChain arg2) throws IOException, ServletException {
		HttpServletRequest req = (HttpServletRequest) arg0;
		HttpSession session = req.getSession();
		System.out.println("--------------session id-------------------------");
		System.out.println(session.getId());
		arg2.doFilter(arg0, arg1);
	}

	public void init(FilterConfig arg0) throws ServletException {
		// TODO Auto-generated method stub

	}

}



同一个客户端连续请求2次的打印结果:

--------------session id-------------------------
EC901AF3E6C895925B2DB007EBC1F833
--------------session id-------------------------
712C18CA3D926013613FBABCD2925560
4 楼 huangpengxiao 2007-05-24  
通宵?
3 楼 Readonly 2007-05-24  
Qieqie 写道

2)获取request.getSession(),打印sessionId
通过打印,看出每一次调用打印的sessionId都不一样,所以试图直接使用HttpSession保持会话是不行的。

你肯定实验错了,后面的一堆烦琐的解决方案先不看了,把你的测试代码放出来。
用Hessian解决Stateful的问题很简单,多加一个Filter,把session里面的用户标识读到就可以了。
2 楼 Qieqie 2007-05-24  
终极解决-底层架构代码展示
1、Current代码
public abstract class Current {
	private static final ThreadLocal<Object[]> data = new ThreadLocal<Object[]>();

	public static void setAttachemnts(Object[] attachments) {
		data.set(attachments);
	}

	public static Object[] getAttachments() {
		return data.get();
	}
}

2、Deletegate接口
public interface Delegate {

	public Object call(String targetBeanName, String methodName, Object[] args,
			Object[] attachments);
}


3、DelegateImpl代码
public class DelegateImpl implements Delegate, ApplicationContextAware {
	// Spring上下文
	private ApplicationContext applicationContext;

	// 缓存从applicationContext得到的bean
	private Map<String, Object> beans = new HashMap<String, Object>();

	private static final Log log = LogFactory.getLog(Delegate.class);

	public void setApplicationContext(ApplicationContext applicationContext)
			throws BeansException {
		this.applicationContext = applicationContext;
	}

	public ApplicationContext getApplicationContext() {
		return applicationContext;
	}

	public Object call(String serviceBeanName, String methodName,
			Object[] args, Object[] attachments) {
		if (log.isDebugEnabled()) {
			StringBuilder sb = new StringBuilder();
			sb.append("-------------------------------call delegate for ")
					.append(serviceBeanName).append('.').append(methodName)
					.append("\n attchments: ");
			for (Object a : attachments) {
				sb.append(a).append(", ");
			}
			sb.setLength(sb.length() - 2);
			log.debug(sb.toString());
		}
		if (attachments != null) {
			Current.setAttachemnts(attachments);//!!这里把attachments设置到Current
		}
		Object bo = getBean(serviceBeanName);
		Class<?>[] argClasses = new Class[args.length];
		for (int i = 0; i < argClasses.length; i++) {
			argClasses[i] = args[i].getClass();
		}
		Method method = null;
		try {
			method = bo.getClass().getMethod(methodName, argClasses);
		} catch (Exception e) {
			throw new InvocationFailureException(e.getMessage(), e);
		}
		if (log.isDebugEnabled()) {
			log.debug("found method named '" + methodName + "' of bean "
					+ serviceBeanName);
		}
		Object ret = null;
		try {
			ret = method.invoke(bo, args);
		} catch (IllegalArgumentException e) {
			throw new InvocationFailureException(e.getMessage(), e);
		} catch (IllegalAccessException e) {
			throw new InvocationFailureException(e.getMessage(), e);
		} catch (InvocationTargetException e) {
			throw new InvocationFailureException(e.getMessage(), e);
		}
		if (log.isDebugEnabled()) {
			log.debug("successfully completed invocation for "
					+ serviceBeanName + '.' + methodName);
		}
		return ret;
	}

	protected Object getBean(String serviceBeanName) {
		Object bean = beans.get(serviceBeanName);
		if (bean == null) {
			bean = applicationContext.getBean(serviceBeanName);
			beans.put(serviceBeanName, bean);
		}
		return bean;
	}

}


4、RemoteProxyBean代码
public class RemoteProxyBean implements MethodInterceptor, InitializingBean,
		FactoryBean, ApplicationContextAware {

	// 业务对象接口,比如com.xxx.bo.UserBo
	private Class serviceInterface;

	// 业务对象在服务器中的名称,比如userBo,由本类从applicationContext自动读入(配置本类的bean标识)
	private String serviceBeanName;

	// 暴露给客户端使用的代理对象,以serviceInterface的名义
	private Object serviceProxy;

	// 服务端暴露的远程代理接口
	private Delegate delegate;

	// Spring上下文
	private ApplicationContext applicationContext;

	// 附加信息来源
	private Attachments attachments;

	//attachments,delegate,applicationContext,serviceInterface getter/setters here

	public Object getObject() throws Exception {
		return this.serviceProxy;
	}

	public Class getObjectType() {
		return getServiceInterface();
	}

	public boolean isSingleton() {
		return true;
	}

	public void afterPropertiesSet() {
		readServiceBeanName();
		this.serviceProxy = ProxyFactory.getProxy(getServiceInterface(), this);
	}

	protected void readServiceBeanName() {
		String[] names = applicationContext
				.getBeanNamesForType(RemoteProxyBean.class);
		for (String name : names) {
			Object maybe = applicationContext.getBean(name);
			if (maybe == this) {
				this.serviceBeanName = name;
				break;
			}
		}
		if (this.serviceBeanName == null) {
			throw new IllegalArgumentException();
		}
		//Spring会对FacotryBean的名称前面将&,我们要把它去掉
		int index = this.serviceBeanName.indexOf('&');
		this.serviceBeanName = this.serviceBeanName.substring(index + 1);
	}

	public Object invoke(MethodInvocation invocation) throws Throwable {
		Object [] attachments = null;
		if (this.attachments != null) {
			attachments = this.attachments.get();
		}
		return delegate.call(serviceBeanName, invocation.getMethod().getName(),
				invocation.getArguments(), attachments);
	}

}



5、Attachments接口
public interface Attachments {

	public Object[] get();
}


6、SimpleAttachments
/**
 * 最简单的实现,用于单用户的客户端。
 * 多用户的客户端,应该另外实现。
 * 
 * @author zhiliang.wang
 *
 */
public class SimpleAttachments implements Attachments {
	
	private Object[] values;

	public Object[] get() {
		return values;
	}

	public void set(Object[] values) {
		this.values = values;
	}

}
1 楼 Qieqie 2007-05-24  
终极解决 - 编程代码展示
1、UserBo(仅为示例用,没有考虑接口设计是否完全合理):
public interface UserBo {
    public User login(String name, String password);
    public void updateProfile(String signature);
}


2、客户端登录代码
User user = userBo.login("wang", "xxxxxx");
SimpleAttachments attachments = (SimpleAttachments )getBean("attachments");//SimpleAttachments 是这个方案中的一个接口,只有一对get/set方法;getBean指的是从client端的applicationContext.xml读
attachments.set(new Object[]{user.getId(), user.getToken(), user.getLastLoginTime()});


3、客户端修改资料代码
userBo.updateProfile("签名是用来做什么的,有什么意义?");


4、客户端applicationContext.xml片段
	<bean id="remoteProxyBean" abstract="true" class="xxx.RemoteProxyBean">
		<property name="delegate">
			<bean
				class="org.springframework.remoting.caucho.HessianProxyFactoryBean">
				<property name="serviceUrl" value="${remoting}delegate" />
				<property name="serviceInterface"
					value="xxx.Delegate" />
			</bean>
		</property>
		<property name="attachments" ref="attachments"></property>
	</bean>
	
	<bean id="attachments" class = "xxx.SimpleAttachements">
	</bean>

	<bean id="userBo" parent="remoteProxyBean">
		<property name="serviceInterface" value="xxx.UserBoImpl" />
	</bean>


5、服务端UserBo实现
public User login(String name, String password){
    User user = userDao.getByName(name);
    if (user != null && user.getPassword().equals(password))  {
         user.setLastLoginTime(new Date());
         user.setToken("随机生成的类似session id的一个字符串,和userId,当前时间有关");
         return user;
    }
    return null;
}

public void updateProfile(String signature) {
    Object[] attachements = Current.getAttachements();//注意这个Current类
     //attachements==null的情况,我们可以通过配置AOP拦截掉,使这里的attachements不会为null
    Long userId = attachements[0];
    //attachements不合法,比如Token被恶意改写的情况,同样可以配置AOP或Filter在调用本方法之前就验证了,这里我们就认为是合法的便可以
    User user = userDao.getById(userId);
    user.setSignature(signature);
}


6、服务端remoting-servlet.xml配置片段
	<bean name="/delegate"
		class="org.springframework.remoting.caucho.HessianServiceExporter">
		<property name="service" ref="delegate" />
		<property name="serviceInterface" value="xxx.Delegate" />
	</bean>
	
	<bean name="delegate" class="xxx.DelegateImpl" />

7、服务端applicationContext-bo.xml配置片段
<bean id="userBo" class="xxx.UserBoImpl" autowire="byName"/>

相关推荐

    AIGC-基于ControlNet的AI视频生成算法-支持动漫+写实风格转换-附项目源码+流程教程-优质项目实战

    AIGC_基于ControlNet的AI视频生成算法_支持动漫+写实风格转换_附项目源码+流程教程_优质项目实战

    wjf0214_qd-templates_1742851862.zip

    app开发

    毕业设计指南-word

    毕业设计指南-word

    《基于YOLOv8的无人便利店监控系统》(包含源码、完整数据集、可视化界面、部署教程)简单部署即可运行。功能完善、操作简单,适合毕设或课程设计.zip

    资源内项目源码是来自个人的毕业设计,代码都测试ok,包含源码、数据集、可视化页面和部署说明,可产生核心指标曲线图、混淆矩阵、F1分数曲线、精确率-召回率曲线、验证集预测结果、标签分布图。都是运行成功后才上传资源,毕设答辩评审绝对信服的保底85分以上,放心下载使用,拿来就能用。包含源码、数据集、可视化页面和部署说明一站式服务,拿来就能用的绝对好资源!!! 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、大作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.txt文件,仅供学习参考, 切勿用于商业用途。

    渗透测试之信息收集思维导图

    信息收集思维导图

    三维偏微分方程组的数值解法与一阶近似推导-基于有限差分法的Python实现(复现论文或解决问题,含详细可运行代码及解释)

    内容概要:本文详细介绍了三维偏微分方程组的数值解法及其一阶近似的推导过程。首先,针对定义在一个三维立方体域上的六个耦合偏微分方程组,选择了有限差分法(FDM)作为数值求解的方法。文中提供了详细的离散化步骤、边界条件设定以及迭代求解的具体实现,并附带了完整的Python代码用于求解和可视化结果。其次,通过对六个方程的线性组合,推导出了一阶近似方程,证明了在特定条件下,系统的演化可以由一个扩散方程来描述。最后,对不同参数σ下的数值结果进行了分析,展示了不同σ值对解的影响。 适合人群:具备数学建模和编程基础的研究人员和技术爱好者,尤其是对偏微分方程数值解感兴趣的学者。 使用场景及目标:适用于需要解决复杂物理现象模拟的问题,如流体力学、热传导等领域。通过学习本文,读者能够掌握有限差分法的基本思想和应用技巧,同时理解如何利用Python进行科学计算和数据可视化。 其他说明:本文不仅提供理论推导,还给出了具体的代码实现,便于读者理解和复现实验结果。此外,文中涉及的可视化部分可以帮助直观地展示数值解的特点和变化趋势。

    大数据项目深度研究分析报告.docx

    大数据项目深度研究分析报告.docx

    连接打印机0x0000709错误修复方法

    对于WIN11系统连接共享打印机出现提示:windows无法连接到打印机,请检查 打印机名并重试,以及“操作无法完成(错误 0x00000709)”等提示进行解决。

    Docker入门与实战指南:镜像与容器的全流程解析

    内容概要:本文详细介绍了Docker的重要概念、常用指令及其应用场景,旨在帮助初学者快速掌握Docker的使用方法。主要内容涵盖镜像和容器的概念区分、镜像的获取方式(网络拉取、本地加载)、镜像的使用(查看、创建容器、删除)、容器的管理(进入、退出、停止、删除)、镜像的生成(自动构建、手动提交)以及镜像的分享(在线存储库、本地导出)。此外,还涉及了无用数据的清理和一些常用的可视化管理工具。 适合人群:对Docker感兴趣的初学者,尤其是希望快速上手并应用于实际项目的开发人员。 使用场景及目标:适用于需要快速搭建一致运行环境、进行应用部署和维护的技术团队。通过学习本文,读者能够独立完成Docker环境的搭建、镜像和容器的管理,从而提高开发效率和环境一致性。 其他说明:文中提供了丰富的实例和官方文档链接,便于读者深入理解和实践。同时,附带了一些实用的参考资料,方便进一步探索Docker的高级特性。

    鞍山市乡镇边界,矢量边界,shp格式

    矢量边界,行政区域边界,精确到乡镇街道,可直接导入arcgis使用

    动态综合评价中的无量纲化方法及其Python实现(复现论文,含详细可运行代码及解释)

    内容概要:本文详细介绍了动态综合评价中的无量纲化方法,并提供了Python代码实现。主要内容包括:数据准备、静态无量纲化方法(极差法、Z-score标准化、均值法)、三种动态无量纲化改进方法(标准序列法、全序列法、增量权法)。文中还进行了结果分析与比较,得出了全序列法是最推荐的方法,因其能够同时保留横向和纵向信息。最后,文章展示了如何将这些方法应用于TOPSIS综合评价系统,以及如何通过熵权法计算权重。 适合人群:具备一定数据分析和编程基础的研究人员、数据科学家、工程师。 使用场景及目标:适用于需要对多维时序数据进行无量纲化处理和综合评价的场景,如生产质量监控、供应商评估等。目标是帮助用户理解和实现动态综合评价中的无量纲化方法,提高数据处理和分析能力。 其他说明:本文不仅提供了详细的代码实现,还通过实例验证了不同方法的效果,确保读者能够深入理解每种方法的特点和应用场景。

    腾讯AI封装调用,针对腾讯的AI产品进行封装调用

    腾讯AI封装调用

    《基于YOLOv8的零售商品识别系统》(包含源码、完整数据集、可视化界面、部署教程)简单部署即可运行。功能完善、操作简单,适合毕设或课程设计.zip

    资源内项目源码是来自个人的毕业设计,代码都测试ok,包含源码、数据集、可视化页面和部署说明,可产生核心指标曲线图、混淆矩阵、F1分数曲线、精确率-召回率曲线、验证集预测结果、标签分布图。都是运行成功后才上传资源,毕设答辩评审绝对信服的保底85分以上,放心下载使用,拿来就能用。包含源码、数据集、可视化页面和部署说明一站式服务,拿来就能用的绝对好资源!!! 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、大作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.txt文件,仅供学习参考, 切勿用于商业用途。

    路径规划领域中A*算法的优化与改进及其应用场景

    内容概要:本文详细介绍了A*算法的传统框架及其在路径规划中的局限性,并提出了多项改进措施。首先,针对启发函数进行了优化,引入了基于机器学习的预测方法以及动态权重调整,使得路径更加智能化和平滑化。其次,在邻接表和优先队列方面采用了更高效的数据结构,提高了算法的执行效率。实验结果显示,改进后的A*算法不仅缩短了路径长度,还显著降低了运行时间和空间开销。此外,作者对比了多种常见路径规划算法(如Dijkstra、RRT),展示了改进A*算法在不同场景下的优越性能。 适合人群:从事机器人导航、自动驾驶、游戏开发等领域研究的技术人员,尤其是对路径规划算法有一定了解并希望深入探索优化方法的研究者。 使用场景及目标:①需要在二维或三维环境中进行高效路径规划的应用场合;②希望通过优化现有算法来提升系统性能的研发团队;③希望掌握更多关于路径规划理论和技术细节的学习者。 其他说明:文中提供了具体的MATLAB代码片段用于解释各个部分的具体实现方式,并分享了一些实用技巧,如优先队列的容器映射实现和动画绘制优化等。

    食品菜单_侧滑功能_列表展示_通用APP开发框架_1742855562.zip

    app开发

    word-【软考-网络工程师】学习资源

    网络工程师(中级)是软考(计算机技术与软件专业技术资格考试)的一部分,主要考察计算机网络基础、网络安全、网络管理、操作系统、数据库等内容,考试分为上午的基础知识选择题和下午的案例分析题。

    IoT最新进展111222

    IoT最新进展

    《基于YOLOv8的顾客行为分析系统》(包含源码、完整数据集、可视化界面、部署教程)简单部署即可运行。功能完善、操作简单,适合毕设或课程设计.zip

    资源内项目源码是来自个人的毕业设计,代码都测试ok,包含源码、数据集、可视化页面和部署说明,可产生核心指标曲线图、混淆矩阵、F1分数曲线、精确率-召回率曲线、验证集预测结果、标签分布图。都是运行成功后才上传资源,毕设答辩评审绝对信服的保底85分以上,放心下载使用,拿来就能用。包含源码、数据集、可视化页面和部署说明一站式服务,拿来就能用的绝对好资源!!! 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、大作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.txt文件,仅供学习参考, 切勿用于商业用途。

    前端开发_VueCli3_H5模板_集成高德地图MintUI_1742856847.zip

    前端开发_VueCli3_H5模板_集成高德地图MintUI_1742856847.zip

Global site tag (gtag.js) - Google Analytics