首页 文章 精选 留言 我的

精选列表

搜索[分片功能],共10000篇文章
优秀的个人博客,低调大师

Activity多功能按钮——基础编

packagecom.smart; importandroid.app.Activity; importandroid.app.AlertDialog; importandroid.app.Dialog; importandroid.content.DialogInterface; importandroid.os.Bundle; importandroid.util.Log; importandroid.view.View; importandroid.view.View.OnClickListener; importandroid.widget.Button; importandroid.widget.ListView; //继承OnClickListener publicclassMainextendsActivityimplementsOnClickListener{ //固定的静态变量, privatefinalintDELETE_FILE=1; privatefinalintSIMPLE_LIST=2; privatefinalintSINGLE_CHOICE_LIST=3; privatefinalintMULTI_LIST=4; privateListViewlv=null; //定义一个字符串数组 privateString[]provinces=newString[]{"中国","泰国","美国","法国", "新加坡","英国"}; //按钮 privateButtonOnClickbuttonOnClick=newButtonOnClick(1); @Override//事件点击 publicvoidonClick(Viewv){ //开关选择 switch(v.getId()){ caseR.id.btnDeleteFile: showDialog(DELETE_FILE); break; caseR.id.btnSimpleList: showDialog(SIMPLE_LIST); break; caseR.id.btnChoiceList: showDialog(SINGLE_CHOICE_LIST); break; caseR.id.btnMultiChoiceList: showDialog(MULTI_LIST); break; caseR.id.btnRemoveDialog: removeDialog(DELETE_FILE); removeDialog(SIMPLE_LIST); removeDialog(SINGLE_CHOICE_LIST); removeDialog(MULTI_LIST); break; } } @Override protectedDialogonCreateDialog(intid){ Log.d("dialog",String.valueOf(id)); //用来判断选择的目标。如果没有选择,并提示出来,选择中了,也显示结果。详看代码 switch(id){ caseDELETE_FILE: returnnewAlertDialog.Builder(this).setIcon(R.drawable.question).setTitle("是否删除文件").setPositiveButton("确定",newDialogInterface.OnClickListener(){ @Override publicvoidonClick(DialogInterfacedialog,intwhich){ newAlertDialog.Builder(Main.this).setMessage("文件已经被删除").create().show(); } }).setNegativeButton("取消",newDialogInterface.OnClickListener(){ @Override publicvoidonClick(DialogInterfacedialog,intwhich){ newAlertDialog.Builder(Main.this).setMessage("您已经选择了取消,文件未删除").create().show(); } }).create(); caseSIMPLE_LIST: returnnewAlertDialog.Builder(this).setTitle("选择国家").setItems(provinces,newDialogInterface.OnClickListener(){ @Override publicvoidonClick(DialogInterfacedialog,intwhich){ finalAlertDialogad=newAlertDialog.Builder(Main.this).setMessage("您已经选择了"+which+":"+provinces[which]).show(); android.os.Handlerhander=newandroid.os.Handler(); hander.postDelayed(newRunnable(){ //线程管理 @Override publicvoidrun(){ ad.dismiss(); } },5*1000); } }).create(); caseSINGLE_CHOICE_LIST: returnnewAlertDialog.Builder(this).setTitle("选择国家").setSingleChoiceItems(provinces,1,buttonOnClick).setPositiveButton("确定",buttonOnClick).setNegativeButton("取消",buttonOnClick).create(); caseMULTI_LIST: AlertDialogad=newAlertDialog.Builder(this).setIcon(R.drawable.image).setTitle("选择国家").setMultiChoiceItems(provinces,newboolean[]{false,true,false,true,false,false},newDialogInterface.OnMultiChoiceClickListener(){ @Override publicvoidonClick(DialogInterfacedialog,intwhich,booleanisChecked){ } }).setPositiveButton("确定",newDialogInterface.OnClickListener(){ @Override publicvoidonClick(DialogInterfacedialog,intwhich){ intcount=lv.getCount(); Strings="您选择了:"; for(inti=0;i<provinces.length;i++){ if(lv.getCheckedItemPositions().get(i)){ s+=i+":"+lv.getAdapter().getItem(i)+""; } } if(lv.getCheckedItemPositions().size()>0){ newAlertDialog.Builder(Main.this).setMessage(s).show(); }else{ newAlertDialog.Builder(Main.this).setMessage("您未选择任何国家").show(); } } }).setNegativeButton("取消",null).create(); lv=ad.getListView(); returnad; } returnnull; } @Override publicvoidonCreate(BundlesavedInstanceState){ super.onCreate(savedInstanceState); setContentView(R.layout.main); //得到选中的哪一个按钮 ButtonbtnDeletefile=(Button)findViewById(R.id.btnDeleteFile); ButtonbtnSimpleList=(Button)findViewById(R.id.btnChoiceList); ButtonbtnSimngleChoiceList=(Button)findViewById(R.id.btnSimpleList); ButtonbtnMultiChoiceList=(Button)findViewById(R.id.btnMultiChoiceList); ButtonbtnRemoveDialog=(Button)findViewById(R.id.btnRemoveDialog); //绑定监听器 btnDeletefile.setOnClickListener(this); btnSimpleList.setOnClickListener(this); btnSimngleChoiceList.setOnClickListener(this); btnMultiChoiceList.setOnClickListener(this); btnRemoveDialog.setOnClickListener(this); } //定义一个类,用来判断选择中的。 privateclassButtonOnClickimplementsDialogInterface.OnClickListener{ privateintindex; publicButtonOnClick(intindex){ this.index=index; } @Override publicvoidonClick(DialogInterfacedialog,intwhichButton){ if(whichButton>=0){ index=whichButton; }else{ if(whichButton==DialogInterface.BUTTON_POSITIVE){ newAlertDialog.Builder(Main.this).setMessage("您已经选择了:"+index+":"+provinces[index]).show(); }elseif(whichButton==DialogInterface.BUTTON_NEGATIVE){ newAlertDialog.Builder(Main.this).setMessage("你未选择,请选择").show(); } } } } protectedvoidonPrepareDialog(intid,Dialogdialog){ super.onPrepareDialog(id,dialog); } } 另外很多朋友对Android系统构架图还不是很了解,我附上一张中文的图给大家观看 本文转自 llb988 51CTO博客,原文链接:http://blog.51cto.com/llb988/489522,如需转载请自行联系原作者

优秀的个人博客,低调大师

android:eclipse:no proposals没有辅助功能

在mac上刚装完eclipse后,经常使用的eclipse辅助输入的快捷键竟然没有建议,纠结n久,最终还是在stackoverflow找到问题 Tryrestoring the default optionsin 'Windows > Preferences > Java > Editor > Content Assist > Advanced' (example of the kind of data you see in this preference screen, not necessarily what you have though) http://stackoverflow.com/questions/908489/eclipse-java-code-completion-not-working 本文转自老Zhan博客园博客,原文链接:http://www.cnblogs.com/mybkn/archive/2012/05/21/2512172.html,如需转载请自行联系原作者

优秀的个人博客,低调大师

Android CoordinatorLayout(六) 加入下拉功能

上章讲了CoordinatorLayout的卡顿BUG,既然有BUG又没解决,说实话没必要讲下去,但是做事总要有始有终,既然写了就把它写完吧,顶着BUG去写。 四、CoordinatorLayout + 下拉刷新 之前用过,但是在google找不到我心目中的刷新方式,google上写的都是在滑动控件上加一层刷新,而且都是SwipeRefreshLayout。如果你是想实现这样的效果,你直接在google上找代码就是,一大堆。我要做的是在整个CoordinatorLayout 外加一层刷新,入下图的效果。 image.png 我们在CoordinatorLayout+ AppBarLayout + ViewPager这个例子上加下拉刷新框架。 1. 准备 我使用的是PullToRefresh框架,但是我会告诉你,你要用SwipeRefreshLayout的做法也是一样的,下拉框架的原理都是那样。 既然是使用PullToRefresh,就要导入PullToRefresh的Module,用过的都知道,没用过的希望先去了解一下。不懂导入Module的赶紧去学。 2.思路 在实现这样一个框架,你想想,就需要在原来的布局中加入一层上拉下拉框架。简单来说,我们要把CoordinatorLayout+ AppBarLayout + ViewPager放到PullToRefresh的中间部分,也就是PullToRefresh的PullToRefreshBase。那我们就需要先写个PullToRefreshBase代表CoordinatorLayout+ AppBarLayout + ViewPager。 注意: 如果你不会用PullToRefresh框架,你肯定看懵逼我接下来的代码,所以不了解这个框架的一定要先学会这个框架的简单用法,比如你写个demo让PullToRefresh装RecyclerView,等你大概会用了再看我接下去的步骤,我也不想写太多基础上的细节。 3.定义PullToRefreshBase xml布局: <com.example.kylinarm.coordinatorlayouttest.PullRefreshCoordTest android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/pull" > </com.example.kylinarm.coordinatorlayouttest.PullRefreshCoordTest> 布局没什么好解释的。 自定义PullToRefreshBase: public class PullRefreshCoordTest extends PullToRefreshBase<CoordinatorView> { private CoordinatorView coordinatorView; public PullRefreshCoordTest(Context context) { super(context); } public PullRefreshCoordTest(Context context, AttributeSet attrs) { super(context, attrs); } public PullRefreshCoordTest(Context context, Mode mode) { super(context, mode); } public PullRefreshCoordTest(Context context, Mode mode, AnimationStyle animStyle) { super(context, mode, animStyle); } @Override public Orientation getPullToRefreshScrollDirection() { return Orientation.VERTICAL; } @Override protected CoordinatorView createRefreshableView(Context context, AttributeSet attrs) { coordinatorView = new CoordinatorView(context); return coordinatorView; } @Override protected boolean isReadyForPullEnd() { return false; } @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) @Override protected boolean isReadyForPullStart() { // 或者判断CoordinatorView是否全部展开 return coordinatorView.getScrollY() == 0 && coordinatorView.getmVerticalOffset() >= 0; } public CoordinatorView getCoordinatorView() { return coordinatorView; } } 介绍: (1)CoordinatorView就是我们的CoordinatorLayout+ AppBarLayout + ViewPager,等下会放这个view具体处理的代码。 (2)createRefreshableView()方法就是创建嵌套在PullToRefresh里面的view,这是基础。 (3)isReadyForPullStart(),这个方法很重要,是判断什么时候可以下拉刷新,里面是一个算法,这个算法我放到最后讲。 4. 定义CoordinatorView(CoordinatorLayout+ AppBarLayout + ViewPager) public class CoordinatorView extends FrameLayout { @InjectView(R.id.tl_tab) TabLayout tlTab; @InjectView(R.id.vp_content) MyViewPager vpContent; @InjectView(R.id.appbar) AppBarLayout appbar; private View contentView; //记录是否处于展开状态 public int mVerticalOffset = 0; private String[] titles = {"tab1","tab2"}; private List<Fragment> fragments = new ArrayList<>(); private Context context; private FragmentActivity fActivity; public CoordinatorView(Context context) { super(context); this.context = context; if (context instanceof FragmentActivity){ fActivity = (FragmentActivity) context; } init(); } private void init(){ contentView = LayoutInflater.from(getContext()).inflate(R.layout.activity_cv,null); contentView.setLayoutParams(new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT)); addView(contentView); ButterKnife.inject(this,contentView); appbar.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() { @Override public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) { mVerticalOffset = verticalOffset; } }); } public void initView(){ for (int i = 0; i < titles.length; i++) { tlTab.addTab(tlTab.newTab().setText(titles[i])); } fragments = setFragmentList(); vpContent.setAdapter(new FragmentPagerAdapter(fActivity.getSupportFragmentManager()) { @Override public int getCount() { return titles.length; } @Override public Fragment getItem(int position) { return fragments.get(position); } @Override public CharSequence getPageTitle(int position) { if (null != titles) { return titles[position]; } return super.getPageTitle(position); } }); tlTab.setupWithViewPager(vpContent); } private List<Fragment> setFragmentList(){ List<Fragment> fragmentList = new ArrayList<>(); fragmentList.add(new ListFragment()); fragmentList.add(new ImageFragment()); return fragmentList; } public int getmVerticalOffset() { return mVerticalOffset; } } 其实这里的代码很容易看到,就是CoordinatorLayout+ AppBarLayout + ViewPager的正常操作,不过加了一步很重要的方法: 在init()中 appbar.addOnOffsetChangedListener(new AppBarLayout.OnOffsetChangedListener() { @Override public void onOffsetChanged(AppBarLayout appBarLayout, int verticalOffset) { mVerticalOffset = verticalOffset; } }); 这里是给AppBarLayout加了一个监听事件addOnOffsetChangedListener,这个监听是什么意思呢?就是监听折叠。这个方法中的verticalOffset表示的是...我也不懂怎么解释好,我就告诉你,当AppBarLayout处于完全展开状态,verticalOffset为0,而当你折叠的时候verticalOffset就变成负数,完全折叠时verticalOffset就变成负的AppBarLayout内折叠控件的高度。这个属性和判断什么时候能下拉有关,一定要先了解。 5.判断下拉 我们在PullRefreshCoordTest 的isReadyForPullStart方法中写了一个算法来判断什么时候能下拉,现在我们在了解完上面的代码之后来讲讲这个算法。 protected boolean isReadyForPullStart() { // 或者判断CoordinatorView是否全部展开 return coordinatorView.getScrollY() == 0 && coordinatorView.getmVerticalOffset() >= 0; } (1)coordinatorView.getScrollY()这个不用讲了,很容易懂 (2)coordinatorView.getmVerticalOffset() >= 0; 什么意思呢?coordinatorView.getmVerticalOffset() 能返回我们第4步中讲的verticalOffset,上面我们说过完全展开的时候是0,折叠之后变成负数。也就是说这句话的意思是完全展开时才能让这个view刷新。 其实也不是很难理解,多看两次代码就能看懂了。记住,要想让CoordinatorLayout刷新,只有在它处于完全展开的时候才能刷新。

优秀的个人博客,低调大师

iOS功能测试工具 Frank

Frank 也是一款深受开发者喜爱的 iOS 应用 测试 框架,该框架可以模拟用户操作对应用程序进行 黑盒测试 ,并使用Cucumber作为自然语言来编写 测试用例 。此外,Frank还会对应用测试操作进行记录,以帮助开发者进行测试回顾。 一、基本介绍 Frank是ios开发环境下一款实现自动测试的工具。 Xcode环境下开发完成后,通过Frank实现结构化的测试用例,其底层语言为 Ruby。作为一款开源的iOS测试工具,在国外已经有广泛的应用。但是国内相关资料却比较少。其最大的优点是允许我们用熟悉的自然语言实现实际的操作逻辑。 一般而言,测试文件由一个.feature文件和一个.rb文件组成。.feature文件包含的是测试操作的自然语言描述部分,内部可以包含多个测试用例,以标签(@tagname)的形式唯一标识,每个用例的首行必须有Scenario: some description;.rb文件则是ruby实现逻辑,通过正则表达式匹配.feature文件中的每一句自然语言,然后执行相应的逻辑操作,最终实现自动测试的目的。 二、安装 1. Terminal 输入sudo gem install frank-cucumber,下载并安装Frank 2. Terminal 进入工程所在路径,工程根目录 3. 输入:frank-skeleton,会在工程根目录新建Frank文件夹 4. 返回Xcode界面,右键Targets下的APP,选择复制,Duplicate only 5. 双击APPname copy,更改副本名,例如 Appname Frankified 6. 右击APP,Add Files to Appname…… 7. 勾选副本,其余取消选定。选择新建的Frank文件夹,Add. 8. 选择APP,中间部分Build Phases选项卡,Link Binary With LibrariesàCFNetwork.framework,Add. 9. 依旧中间部分,选择Build Settings选项卡,Other Linker Flags,双击,添加“-all_load”和“ObjC” 10. 左上角,Scheme Selector,在RUN和STOP按钮的右边,选择Appname copy-IPHONE 11. 浏览器中打开http://localhost:37265,可以在浏览器中看到植入Frank的应用 我在添加了两个flag之后老是报错,尝试了N种方法之后索性全部删掉,结果就可以了,无语 三、基本步骤 1. terminal 切换到Frank文件夹所在目录 2. frank launch, 打开simulator,开始运行(默认是用IPHONE simulator,要用IPAD simulator时,需要如下命令行,添加参数:frank launch --idiom ipad) 3. cucumber Frank/features/my_first.feature --tags @tagname (注意tags前面两个‘-’)PS:如果没有tag则自动运行文件中所有case 最新内容请见作者的GitHub页:http://qaseven.github.io/

优秀的个人博客,低调大师

ODPS功能介绍之数据导入

在使用ODPS强大的数据处理能力之前,大家最关心的是自己的数据如何导入到ODPS中。 下面介绍一款向ODPS导入数据的工具-Fluentd。 Fluentd是一个开源的软件,用来收集各种源头日志(包括Application Log、Sys Log及Access Log),允许用户选择插件对日志数据进行过滤、并存储到不同的数据处理端(包括MySQL、Oracle、MongoDB、Hadoop、Treasure Data、AWS Services、Google Services以及ODPS等)。Fluentd以小巧灵活而著称,允许用户自定义数据源、过滤处理及目标端等插件,目前在这款软件中已经有300+个插件运行Fluentd的架构上,而且这些插件全部是开源的。 ODPS也在这款软件上开源了数据导入插件。 环境准备 使用这款软件,向ODPS导入数据,需要具备如下环境: Ruby 2.1.0 或更新 Gem 2.4.5 或更新 Fluentd-0.10.49 或从Fluentd 官网http://www.fluentd.org/ 查找最新,Fluentd为不同的OS提供了不同的版本,详见http://docs.fluentd.org/articles/quickstart Protobuf-3.5.1 或更新(Ruby protobuf) 安装导入插件 接下来可以通过以下两种方式中的任意一种来安装ODPS Fluentd 导入插件。 方式一:通过ruby gem安装: $ gem install fluent-plugin-aliyun-odps ODPS已经将这个插件发布到GEM库中, 名称为 fluent-plugin-aliyun-odps,只需要通过gem install 命令来安装即可(大家在使用gem 时在国内可能会遇到gem库无法访问,可以在网上搜一下更改gem 库源来解决)。 方式二:通过插件源码安装: $ gem install protobuf $ gem install fluentd –no-ri –no-rdoc $ git clone https://github.com/aliyun/aliyun-odps-fluentd-plugin.git $ cp aliyun-odps-fluentd-plugin/lib/fluent/plugin/* {YOUR_FLUENTD_DIRECTORY}/lib/fluent/plugin/ -r 其中第二条命令是安装fluentd,如果已经安装可以省略。 ODPS Fluentd插件源码在github上,clone下来之后直接放到Fluentd的plugin目录中即可。 插件的使用 使用Fluentd导入数据时,最主要的是配置Fluentd的conf文件,更多conf文件 的介绍请参见: http://docs.fluentd.org/articles/config-file 示例一:导入Nginx日志 。Conf中source的配置如下: <source> type tail path /opt/log/in/in.log pos_file /opt/log/in/in.log.pos refresh_interval 5s tag in.log format /^(?<remote>[^ ]*) – - \[(?<datetime>[^\]]*)\] “(?<method>\S+)(?: +(?<path>[^\"]*?)(?: +\S*)?)?” (?<code>[^ ]*) (?<size>[^ ]*) “-” “(?<agent>[^\"]*)”$/ time_format %Y%b%d %H:%M:%S %z </source> fluentd 以tail方式监控指定的文件内容是否有变化,更多的tail配置参见:http://docs.fluentd.org/articles/in_tail match 配置如下: <match in.**> type aliyun_odps aliyun_access_id ************ aliyun_access_key ********* aliyun_odps_endpoint http://service.odps.aliyun.com/api aliyun_odps_hub_endpoint http://dh.odps.aliyun.com buffer_chunk_limit 2m buffer_queue_limit 128 flush_interval 5s project projectforlog <table in.log> table nginx_log fields remote,method,path,code,size,agent partition ctime=${datetime.strftime(‘%Y%m%d’)} time_format %d/%b/%Y:%H:%M:%S %z </table> </match> 数据会导入到projectforlog project的nginx_log表中,其中会以源中的datetime字段作为分区,插件遇到不同的值时会自动创建分区; 示例二:导入MySqL中的数据。导入MySQL中数据时,需要安装fluent-plugin-sql插件作为source: $ gem install fluent-plugin-sql 配置conf中的source: <source> type sql host 127.0.0.1 database test adapter mysql username xxxx password xxxx select_interval 10s select_limit 100 state_file /path/sql_state <table> table test_table tag in.sql update_column id </table> </source> 这个例子是从test_table中SELECT数据,每间隔10s去读取100条数据出来,SELECT 时将ID列作为主键(id字段是自增型)。关于fluent-plugin-sql的更多说明参见:https://github.com/fluent/fluent-plugin-sql match 配置如下: <match in.**> type aliyun_odps aliyun_access_id ************ aliyun_access_key ********* aliyun_odps_endpoint http://service.odps.aliyun.com/api aliyun_odps_hub_endpoint http://dh.odps.aliyun.com buffer_chunk_limit 2m buffer_queue_limit 128 flush_interval 5s project your_projectforlog <table in.log> table mysql_data fields id,field1,field2,fields3 </table> </match> 数据会导出到ODPS projectforlog project的mysql_data表中,导入的字段包括id,field1,field2,field3。 关于导入表的说明 通过Fluentd导入数据是走的ODPS实时数据流入通道-Datahub,这个通道需要一个特殊的ODPS表,这个表在创建时需要指定为Hub Table。创建表时可以使用如下语名: CREATE TABLE <table_name) (field_name type,…) PARTITIONED BY (pt_name type) INTO <n1> SHARDSHUBLIFECYCLE <n2>; 其中:n1 是指shards数量,有效值为1-20。在导入数据时,每个shard的流入量是10M/秒。N2是指数据在Datahub上的保留期,有效值1-7,主要用于流计算场景中使用历史数据。 例如: createtableaccess_log(f1string,f2string,f3string,f4string,f5string,f6string,f7 string)partitionedby(ctimestring)into5shardshublifecycle7; 如果向已经存在的表导入数据,也需要将表修改为HUB表, 其命令为: ALTER TABLE table_name ENABLE HUTTABLE with <n1> SHARDS HUBLIFECYCLE <n2>; 插件参数说明 向ODPS导入数据,需要将ODPS插件配置在conf文件中match项中。插件支持的参数说明如下: type(Fixed): 固定值 aliyun_odps. aliyun_access_id(Required):云账号access_id. aliyun_access_key(Required):云账号access key. aliyun_odps_hub_endpoint(Required):如果你的服务部署在ESC上,请把本值设定为http://dh-ext.odps.aliyun-inc.com, 否则设置为http://dh.odps.aliyun.com. aliyunodps_endpoint(Required):如果你的服务部署在ESC上,请把本值设定为http://odps-ext.aiyun-inc.com/api, 否则设置为http://service.odps.aliyun.com/api. buffer_chunk_limit(Optional): 块大小,支持“k”(KB),“m”(MB),“g”(GB)单位,默认 8MB,建议值2MB. buffer_queue_limit(Optional): 块队列大小,此值与buffer_chunk_limit共同决定整个缓冲区大小。 flush_interval(Optional): 强制发送间隔,达到时间后块数据未满则强制发送, 默认 60s. project(Required): project名称. table(Required): table名称. fields(Required): 与source对应,字段名必须存在于source之中. partition(Optional):若为分区表,则设置此项. 分区名支持的设置模式: 固定值: partition ctime=20150804 关键字: partition ctime=${remote} (其中remote为source中某字段) 时间格式关键字: partition ctime=${datetime.strftime(‘%Y%m%d’)} (其中datetime为source中某时间格式字段,输出为%Y%m%d格式作为分区名称) time_format(Optional):如果使用时间格式关键字为<partition>, 请设置本参数. 例如: source[datetime]=”29/Aug/2015:11:10:16 +0800″,则设置<time_format>为”%d/%b/%Y:%H:%M:%S %z” 更多 除了使用Fluentd可以导入数据外,ODPS还支持通过Flume导入数据。Flume是Apache的一款开源软件,ODPS团队基于Flume开源了导入插件源代码,感兴趣的朋友可以参见https://github.com/aliyun/aliyun-odps-flume-plugin 了解更多细节。

资源下载

更多资源
Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

用户登录
用户注册