- 浏览: 5982 次
-
最新评论
-
PROFANS:
博主,你好。其实我在考虑登录成功之后直接调用我们系统的浏览器去 ...
SWING实现新浪微博客户端(1)自动登录功能 -
liuxiang00435057:
没有源码啊,郁闷
桌面整合—实现跨系统数据交互 -
wenzhangli:
wxwdt 写道有些应用获取可以采用ESB总线的方式,但是有些 ...
桌面整合——应用整合之道 -
wenzhangli:
fireq3 写道说的蛮好,不过要考虑的方面很多,安全性,易用 ...
桌面整合——应用整合之道 -
tsoukw:
不错,现在企业应用太需要整合了
桌面整合——应用整合之道
最近在做一些,基于浏览器的应用整合项目。使用到了DJNative (一种JAVA浏览器实现http://sourceforge.net/projects/djproject/files/DJ%20Native%20Swing/0.9.9%20preview/DJNativeSwing-SWT-0-9-9-20110224.zip/download),对于一些进行接口开发的业务整合系统,提供了一种不错的思路。周末兴趣所致,写了一个新浪微博自动登录的例子。
实现一下功能:1,如果已经登录过的用户,读取配置文件中的用户名密码,调用当前页面自动完成登录。
2,如果未登录用户提示用户输入用户名密码,在用户登录成功后自动截取用户名密码保存到配置文件。
3,当用户名密码出错时清楚已保存的用户名密码,提示用户重新登录。
第一次运行时 提示没有从配置文件中读取到用户名密码
写道
class SsoListener extends WebBrowserAdapter{
public void locationChanged(WebBrowserNavigationEvent e) {
if (e.getNewResourceLocation().equals("http://t.sina.com.cn/")){
String loginname= userProperties.getProperty("loginname") ;
String password= userProperties.getProperty("password") ;
if ((loginname!=null &&!loginname.equals("")) && (password!=null && !loginname.equals(""))){
String script="document.getElementById('loginname').value='"+loginname+"';" +LS+
"document.getElementById('password').value='"+password+"';" +LS+
"document.getElementById('login_submit_btn').click();";
e.getWebBrowser().executeJavascript(script);
}else{
String script="function saveuser(){" +LS+
"sendNSCommand('saveuser',document.getElementById('loginname').value,document.getElementById('password').value);"+LS+
"}" +LS+
"document.getElementById('login_submit_btn').attachEvent('onclick',saveuser);" +LS+
"alert('存储的用户名密码为空,请输入用户名密码')" +LS+
"";
e.getWebBrowser().executeJavascript(script);
e.getWebBrowser().removeWebBrowserListener(this);
e.getWebBrowser().addWebBrowserListener(new ReLoginListener());
}
}else{
System.out.println(e.getNewResourceLocation());
}
}
}
public void locationChanged(WebBrowserNavigationEvent e) {
if (e.getNewResourceLocation().equals("http://t.sina.com.cn/")){
String loginname= userProperties.getProperty("loginname") ;
String password= userProperties.getProperty("password") ;
if ((loginname!=null &&!loginname.equals("")) && (password!=null && !loginname.equals(""))){
String script="document.getElementById('loginname').value='"+loginname+"';" +LS+
"document.getElementById('password').value='"+password+"';" +LS+
"document.getElementById('login_submit_btn').click();";
e.getWebBrowser().executeJavascript(script);
}else{
String script="function saveuser(){" +LS+
"sendNSCommand('saveuser',document.getElementById('loginname').value,document.getElementById('password').value);"+LS+
"}" +LS+
"document.getElementById('login_submit_btn').attachEvent('onclick',saveuser);" +LS+
"alert('存储的用户名密码为空,请输入用户名密码')" +LS+
"";
e.getWebBrowser().executeJavascript(script);
e.getWebBrowser().removeWebBrowserListener(this);
e.getWebBrowser().addWebBrowserListener(new ReLoginListener());
}
}else{
System.out.println(e.getNewResourceLocation());
}
}
}
输入用户名密码:
输入用户名密码成功:成功登录
这时已将用户名密码保存到userProperties.properties中
再次运行时将自动完成新浪微博的登录!
完整的代码如下:
import java.awt.BorderLayout; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.util.Properties; import javax.swing.BorderFactory; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.SwingUtilities; import chrriis.common.UIUtils; import chrriis.dj.nativeswing.swtimpl.NativeInterface; import chrriis.dj.nativeswing.swtimpl.components.JWebBrowser; import chrriis.dj.nativeswing.swtimpl.components.WebBrowserAdapter; import chrriis.dj.nativeswing.swtimpl.components.WebBrowserCommandEvent; import chrriis.dj.nativeswing.swtimpl.components.WebBrowserNavigationEvent; public class SSOSina extends JPanel { protected static final String LS = System.getProperty("line.separator"); private static final String loginUrl="http://t.sina.com.cn"; private static Properties userProperties=new Properties(); public SSOSina() { super(new BorderLayout()); InputStream in = this.getClass().getResourceAsStream("userProperties.properties"); if (in == null) { in = Thread.currentThread().getContextClassLoader().getResourceAsStream("userProperties.properties"); if (in == null) { in = this.getClass().getClassLoader().getResourceAsStream("userProperties.properties"); } } try { userProperties.load(in); } catch (IOException e1) { e1.printStackTrace(); } JPanel webBrowserPanel = new JPanel(new BorderLayout()); webBrowserPanel.setBorder(BorderFactory.createTitledBorder("DJNative JAVA浏览器实现 实现新浪微博自动登录")); final JWebBrowser webBrowser = new JWebBrowser(); webBrowser.setBarsVisible(true); webBrowser.setDefaultPopupMenuRegistered(true); webBrowser.setStatusBarVisible(true); webBrowser.navigate(loginUrl); //单点登录自动提交监听器 class SaveUserListener extends WebBrowserAdapter{ @Override public void commandReceived(WebBrowserCommandEvent e) { String command = e.getCommand(); Object[] parameters = e.getParameters(); if("print".equals(command)) { String html = (String)parameters[0] ; System.out.println(html); } if("saveuser".equals(command)) { String loginname = (String)parameters[0] ; String password = (String)parameters[1] ; userProperties.setProperty("loginname", loginname); userProperties.setProperty("password", password); try { String runningURL = (new URL(SaveUserListener.class .getProtectionDomain().getCodeSource().getLocation(), ".")).openConnection().getPermission().getName(); userProperties.save(new FileOutputStream(new File(runningURL+"userProperties.properties")),"changed"); } catch (FileNotFoundException e1) { e1.printStackTrace(); } catch (IOException e1) { e1.printStackTrace(); } } } } class ReLoginListener extends WebBrowserAdapter{ public void locationChanged(WebBrowserNavigationEvent e) { if (e.getNewResourceLocation().equals("http://t.sina.com.cn")){ userProperties.setProperty("loginname", ""); userProperties.setProperty("password", ""); try { String runningURL = (new URL(SaveUserListener.class .getProtectionDomain().getCodeSource().getLocation(), ".")).openConnection().getPermission().getName(); userProperties.save(new FileOutputStream(new File(runningURL+"jdsclient_init.properties")),"changed"); } catch (FileNotFoundException e1) { e1.printStackTrace(); } catch (IOException e1) { e1.printStackTrace(); } String script="function saveuser(){" +LS+ "sendNSCommand('saveuser',document.getElementById('loginname').value,document.getElementById('password').value);"+LS+ "void(0);" +LS+ "}" +LS+ "document.getElementById('login_submit_btn').href=\"javascript:'saveuser()'\";document.getElementById('login_submit_btn').attachEvent('onclick',saveuser);" +LS+ "alert('用户名密码错误请重新输入');" +LS+ ""; e.getWebBrowser().executeJavascript(script); } } } class SsoListener extends WebBrowserAdapter{ public void locationChanged(WebBrowserNavigationEvent e) { if (e.getNewResourceLocation().equals("http://t.sina.com.cn/")){ String loginname= userProperties.getProperty("loginname") ; String password= userProperties.getProperty("password") ; if ((loginname!=null &&!loginname.equals("")) && (password!=null && !loginname.equals(""))){ String script="document.getElementById('loginname').value='"+loginname+"';" +LS+ "document.getElementById('password').value='"+password+"';" +LS+ "document.getElementById('login_submit_btn').click();"; e.getWebBrowser().executeJavascript(script); }else{ String script="function saveuser(){" +LS+ "sendNSCommand('saveuser',document.getElementById('loginname').value,document.getElementById('password').value);"+LS+ "}" +LS+ "document.getElementById('login_submit_btn').attachEvent('onclick',saveuser);" +LS+ "alert('存储的用户名密码为空,请输入用户名密码')" +LS+ ""; e.getWebBrowser().executeJavascript(script); e.getWebBrowser().removeWebBrowserListener(this); e.getWebBrowser().addWebBrowserListener(new ReLoginListener()); } }else{ System.out.println(e.getNewResourceLocation()); } } } webBrowser.addWebBrowserListener(new SaveUserListener()); webBrowser.addWebBrowserListener(new SsoListener()); webBrowserPanel.add(webBrowser, BorderLayout.CENTER); add(webBrowserPanel, BorderLayout.CENTER); } public InputStream loadResource(String name) { InputStream in = this.getClass().getResourceAsStream(name); if (in == null) { in = Thread.currentThread().getContextClassLoader().getResourceAsStream(name); if (in == null) { in = this.getClass().getClassLoader().getResourceAsStream(name); } } return in; } public static void main(String[] args) { UIUtils.setPreferredLookAndFeel(); NativeInterface.open(); SwingUtilities.invokeLater(new Runnable() { public void run() { JFrame frame = new JFrame("测试新浪微博登录"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.getContentPane().add(new SSOSina(), BorderLayout.CENTER); frame.setSize(800, 600); frame.setLocationByPlatform(true); frame.setVisible(true); } }); NativeInterface.runEventPump(); } }
评论
13 楼
PROFANS
2011-09-17
博主,你好。其实我在考虑登录成功之后直接调用我们系统的浏览器去打开更登录成功的网站,而且是登录状态,一直纠结中,未能实现,能否指教一二?谢谢之前我就是用Swing做的用户界面,可以打开指定的网站,在项目里面可以登录成功,但是打开的网站根本没有登录信息,一直纠结中
12 楼
wenzhangli
2011-03-18
itcrown2005 写道
这,这,其实是。。。。。一种倒退
娱乐一把,不过在一些特定的应用范围里,可能会有一些特殊的用途。
比如,在桌面整合中,用户可以通过这种方式完成几乎所的有单点登录功能。
而相较于HTTPCLIENT的数据抓取,这种方式无疑,是一种更轻量级、适用性更强的方案。
11 楼
zzc0000
2011-03-17
看看这个吧,不是swing 强大不强大,而是你会不会用的问题



10 楼
wenzhangli
2011-03-16
sw1982 写道
这篇不错,通过介绍我去看了一下native swing,发现居然swing也发展到这么强大的分支了,居然可以处理html和js
例子中调用的还是本地浏览器的内核,native swing没有实现HTML和JS的解析。但调用SWT的控件后实现了更多一点的功能。
9 楼
sw1982
2011-03-15
这篇不错,通过介绍我去看了一下native swing,发现居然swing也发展到这么强大的分支了,居然可以处理html和js
8 楼
Javac_MyLife
2011-03-15
学习了。第一次接触DJNative。
7 楼
i2534
2011-03-15
昨天看到flyingsaucer,也许可以直接从html生成图片
6 楼
wenzhangli
2011-03-14
glamey 写道
模拟的那个浏览器,能生成快照吗?

/* * Christopher Deckers (chrriis@nextencia.net) * http://www.nextencia.net * * See the file "readme.txt" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ package chrriis.dj.nativeswing.swtimpl.demo.examples.webbrowser; import java.awt.BorderLayout; import java.awt.Dialog; import java.awt.Dimension; import java.awt.FlowLayout; import java.awt.Frame; import java.awt.Window; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.image.BufferedImage; import javax.swing.BorderFactory; import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JDialog; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.SwingUtilities; import chrriis.common.UIUtils; import chrriis.dj.nativeswing.swtimpl.NativeComponent; import chrriis.dj.nativeswing.swtimpl.NativeInterface; import chrriis.dj.nativeswing.swtimpl.components.JWebBrowser; /** * @author Christopher Deckers */ public class FullPageCaptureExample extends JPanel { private static final String LS = System.getProperty("line.separator"); private static final Dimension THUMBNAIL_SIZE = new Dimension(400, 300); public FullPageCaptureExample() { super(new BorderLayout()); JPanel webBrowserPanel = new JPanel(new BorderLayout()); webBrowserPanel.setBorder(BorderFactory.createTitledBorder("Native Web Browser component")); final JWebBrowser webBrowser = new JWebBrowser(); webBrowser.navigate("http://www.google.com"); webBrowserPanel.add(webBrowser, BorderLayout.CENTER); add(webBrowserPanel, BorderLayout.CENTER); // Create an panel with a screen capture button. JPanel southPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 4, 4)); JButton captureButton = new JButton("Full-page capture"); captureButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { String result = (String)webBrowser.executeJavascriptWithResult( "var width = 0;" + LS + "var height = 0;" + LS + "if(document.documentElement) {" + LS + " width = Math.max(width, document.documentElement.scrollWidth);" + LS + " height = Math.max(height, document.documentElement.scrollHeight);" + LS + "}" + LS + "if(self.innerWidth) {" + LS + " width = Math.max(width, self.innerWidth);" + LS + " height = Math.max(height, self.innerHeight);" + LS + "}" + LS + "if(document.body.scrollWidth) {" + LS + " width = Math.max(width, document.body.scrollWidth);" + LS + " height = Math.max(height, document.body.scrollHeight);" + LS + "}" + LS + "return width + '/' + height;"); // This may happen from time to time so we have to fail gracefully. int index = result == null? -1: result.indexOf("/"); if(index < 0) { JOptionPane.showMessageDialog(webBrowser, "An error occurred while capturing the full-page", "Full-page capture failure", JOptionPane.ERROR_MESSAGE); } else { NativeComponent nativeComponent = webBrowser.getNativeComponent(); Dimension originalSize = nativeComponent.getSize(); Dimension imageSize = new Dimension(Integer.parseInt(result.substring(0, index)), Integer.parseInt(result.substring(index + 1))); // We add some artificial spacing because with scrollbars logic it is likely to be wrong... imageSize.width = Math.max(originalSize.width, imageSize.width + 50); imageSize.height = Math.max(originalSize.height, imageSize.height + 50); nativeComponent.setSize(imageSize); BufferedImage image = new BufferedImage(imageSize.width, imageSize.height, BufferedImage.TYPE_INT_RGB); nativeComponent.paintComponent(image); nativeComponent.setSize(originalSize); Window window = SwingUtilities.getWindowAncestor(webBrowser); JDialog dialog; if(window instanceof Frame) { dialog = new JDialog((Frame)window, "Full-page capture", true); } else { dialog = new JDialog((Dialog)window, "Full-page capture", true); } int tWidth = THUMBNAIL_SIZE.width; int tHeight = THUMBNAIL_SIZE.height; final ImageIcon imageIcon; if(imageSize.width <= tWidth && imageSize.height <= tHeight) { imageIcon = new ImageIcon(image); } else { float ratio1 = imageSize.width / (float)imageSize.height; float ratio2 = tWidth / (float)tHeight; int width = ratio1 > ratio2? tWidth: Math.round(tWidth * ratio1 / ratio2); int height = ratio1 < ratio2? tHeight: Math.round(tHeight * ratio2 / ratio1); imageIcon = new ImageIcon(image.getScaledInstance(width, height, BufferedImage.SCALE_SMOOTH)); } dialog.getContentPane().add(new JLabel(imageIcon)); dialog.pack(); dialog.setLocationRelativeTo(window); dialog.setVisible(true); } } }); southPanel.add(captureButton); add(southPanel, BorderLayout.SOUTH); } /* Standard main method to try that test as a standalone application. */ public static void main(String[] args) { UIUtils.setPreferredLookAndFeel(); NativeInterface.open(); SwingUtilities.invokeLater(new Runnable() { public void run() { JFrame frame = new JFrame("DJ Native Swing Test"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.getContentPane().add(new FullPageCaptureExample(), BorderLayout.CENTER); frame.setSize(800, 600); frame.setLocationByPlatform(true); frame.setVisible(true); } }); NativeInterface.runEventPump(); } }
5 楼
ymkyve
2011-03-14
不错,客户端的东西做的很少.DJNative没用过
4 楼
elan1986
2011-03-14
很不错,那个浏览器很不错!
3 楼
itcrown2005
2011-03-14
这,这,其实是。。。。。一种倒退
2 楼
glamey
2011-03-14
模拟的那个浏览器,能生成快照吗?
1 楼
zhaoshun0417
2011-03-14
这个很好,,去年的毕业设计是自动登陆和恢复系统,没思路。
看了这个。。原来是这样实现的
看了这个。。原来是这样实现的
相关推荐
本主题聚焦于使用Java实现对新浪微博的模拟登录,这对于数据分析、信息抓取或自动化测试等应用场景具有重要意义。 【描述】:“新浪微博模拟登陆源代码,java实现,微博数据抓取” 这段描述揭示了几个关键点: 1....
【标题解析】:“sina-weibo.rar_新浪微博”这个标题表明我们关注的是一个与新浪微博相关的项目,它被封装在一个名为...通过深入学习这些知识点,并结合实际代码,可以逐步理解和改善这个基于Java的新浪微博客户端。
ConciseOne通过调用新浪提供的开放接口,实现了用户登录、发布微博、浏览时间线、评论互动等功能。这需要对OAuth授权机制有深入理解,以及对JSON数据格式的解析处理。 3. **用户界面设计** ConciseOne强调简洁,...
哈希表源码
sun_3ck_03_0119
内容概要:本文档详细介绍了基于 MATLAB 实现的 LSTM-AdaBoost 时间序列预测模型,涵盖项目背景、目标、挑战、特点、应用领域以及模型架构和代码示例。随着大数据和AI的发展,时间序列预测变得至关重要。传统方法如 ARIMA 在复杂非线性序列中表现欠佳,因此引入了 LSTM 来捕捉长期依赖性。但 LSTM 存在易陷局部最优、对噪声鲁棒性差的问题,故加入 AdaBoost 提高模型准确性和鲁棒性。两者结合能更好应对非线性和长期依赖的数据,提供更稳定的预测。项目还展示了如何在 MATLAB 中具体实现模型的各个环节。 适用人群:对时间序列预测感兴趣的开发者、研究人员及学生,特别是有一定 MATLAB 编程经验和熟悉深度学习或机器学习基础知识的人群。 使用场景及目标:①适用于金融市场价格预测、气象预报、工业生产故障检测等多种需要时间序列分析的场合;②帮助使用者理解并掌握将LSTM与AdaBoost结合的实现细节及其在提高预测精度和抗噪方面的优势。 其他说明:尽管该模型有诸多优点,但仍存在训练时间长、计算成本高等挑战。文中提及通过优化数据预处理、调整超参数等方式改进性能。同时给出了完整的MATLAB代码实现,便于学习与复现。
1996-2019年各地级市平均工资数据 1、时间:1996-2019年 2、来源:城市nj、各地级市统计j 3、指标:平均工资(在岗职工) 4、范围:295个地级市
AB PLC例程代码项目案例 【备注】 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用!有问题请及时沟通交流。 2、适用人群:计算机相关专业(如计科、信息安全、数据科学与大数据技术、人工智能、通信、物联网、自动化、电子信息等)在校学生、专业老师或者企业员工下载使用。 3、用途:项目具有较高的学习借鉴价值,不仅适用于小白学习入门进阶。也可作为毕设项目、课程设计、大作业、初期项目立项演示等。 4、如果基础还行,或热爱钻研,亦可在此项目代码基础上进行修改添加,实现其他不同功能。 欢迎下载!欢迎交流学习!不清楚的可以私信问我!
内容概要:本文介绍了一种新颖的变压器模型C2Former(Calibrated and Complementary Transformer),专门用于解决RGB图像和红外图像之间的物体检测难题。传统方法在进行多模态融合时面临两个主要问题——模态错位(Modality miscalibration)和融合不准确(fusion imprecision)。作者针对这两个问题提出采用互模交叉注意力模块(Inter-modality Cross-Attention, ICA)以及自适应特征采样模块(Adaptive Feature Sampling, AFS)来改善。具体来说,ICA可以获取对齐并且互补的特性,在特征层面进行更好的整合;而AFS则减少了计算成本。通过实验验证了基于C2Former的一阶段和二阶段检测器均能在现有公开数据集上达到最先进的表现。 适合人群:计算机视觉领域的研究人员和技术人员,特别是从事跨模态目标检测的研究人员,对Transformer架构有一定了解的开发者。 使用场景及目标:适用于需要将可见光和热成像传感器相结合的应用场合,例如全天候的视频监控系统、无人驾驶汽车、无人
上海人工智能实验室:金融大模型应用评测报告-摘要版2024.pdf
malpass_02_0907
C++-自制学习辅助工具
内容概要:本文提供了有关微信生态系统的综合开发指导,具体涵盖了微信机器人的Java与Python开发、全套及特定应用的小程序源码(PHP后台、DeepSeek集成),以及微信公众号的基础开发与智能集成方法。文中不仅给出了各种应用的具体案例和技术要点如图灵API对接、DeepSeek大模型接入等的简述,还指出了相关资源链接以便深度探究或直接获取源码进行开发。 适合人群:有意开发微信应用程序或提升相应技能的技术爱好者和专业人士。不论是初涉者寻求基本理解和操作流程,还是进阶者期望利用提供的资源进行项目构建或是研究。 使用场景及目标:开发者能够根据自身兴趣选择不同方向深入学习微信平台的应用创建,如社交自动化(机器人)、移动互联网服务交付(小程序),或者公众信息服务(公众号)。特别是想要尝试引入AI能力到应用中的人士,文中介绍的内容非常有价值。 其他说明:文中提及的多个项目都涉及到了最新技术栈(如DeepSeek大模型),并且为不同层次的学习者提供从零开始的详细资料。对于那些想要迅速获得成果同时深入了解背后原理的人来说是个很好的起点。
pimpinella_3cd_01_0916
mellitz_3cd_01_0516
schube_3cd_01_0118
AB PLC例程代码项目案例 【备注】 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用!有问题请及时沟通交流。 2、适用人群:计算机相关专业(如计科、信息安全、数据科学与大数据技术、人工智能、通信、物联网、自动化、电子信息等)在校学生、专业老师或者企业员工下载使用。 3、用途:项目具有较高的学习借鉴价值,不仅适用于小白学习入门进阶。也可作为毕设项目、课程设计、大作业、初期项目立项演示等。 4、如果基础还行,或热爱钻研,亦可在此项目代码基础上进行修改添加,实现其他不同功能。 欢迎下载!欢迎交流学习!不清楚的可以私信问我!
AB PLC例程代码项目案例 【备注】 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用!有问题请及时沟通交流。 2、适用人群:计算机相关专业(如计科、信息安全、数据科学与大数据技术、人工智能、通信、物联网、自动化、电子信息等)在校学生、专业老师或者企业员工下载使用。 3、用途:项目具有较高的学习借鉴价值,不仅适用于小白学习入门进阶。也可作为毕设项目、课程设计、大作业、初期项目立项演示等。 4、如果基础还行,或热爱钻研,亦可在此项目代码基础上进行修改添加,实现其他不同功能。 欢迎下载!欢迎交流学习!不清楚的可以私信问我!
AB PLC例程代码项目案例 【备注】 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用!有问题请及时沟通交流。 2、适用人群:计算机相关专业(如计科、信息安全、数据科学与大数据技术、人工智能、通信、物联网、自动化、电子信息等)在校学生、专业老师或者企业员工下载使用。 3、用途:项目具有较高的学习借鉴价值,不仅适用于小白学习入门进阶。也可作为毕设项目、课程设计、大作业、初期项目立项演示等。 4、如果基础还行,或热爱钻研,亦可在此项目代码基础上进行修改添加,实现其他不同功能。 欢迎下载!欢迎交流学习!不清楚的可以私信问我!
智慧用电平台建设解决方案【28页】