首页 文章 精选 留言 我的

精选列表

搜索[快速],共10000篇文章
优秀的个人博客,低调大师

CUBA Framework 7.2 Beta 版发布,企业级应用快速开发平台

大家好, 我们发布了 CUBA Framework 及常用扩展(报表、图表、FTS、BPM) 的7.2 BETA 版。在这个版本中值得关注的变化如下: 支持将 Kotlin 作为第一语言进行开发 现在,安全机制使用 “默认拒绝(denying by default)” 作为默认模式,以前是“默认允许(allowing by default)” 模式。这意味着,除非你显式地授予了主体允许权限,则用户将无法使用它。另外,现在你可以在 java 类中使用注解来定义应用程序的角色、权限、访问组和约束(类似于Spring Boot的注解风格的配置) 现在够在应用程序属性中指定数据库连接、以标准化的方式确定应用程序主目录(Application Home)、标准化日志配置、提供了对 Spring 环境配置(Spring environment profile)的支持,这些变化会使部署变地更加容易 通用UI中的改进:提供了可折叠的侧边菜单、支持新的登录界面、支持在界面描述中进行内联视图定义、简化了标准操作的配置、使表单中的组件的定位更加灵活、以及其它许多改进 可在发行说明中查看完整的更改列表。英文版开发人员手册已经完成了大部分,英文版开发手册完成后我们会开始中文版的同步工作。 repo.cuba-platform.com和dl.bintray.com仓库中已经提供了 7.2.0.BETA 版制件。请使用最新的 CUBA Studio 13 BETA2 迁移现有项目。关于 CUBA Studio 13 BETA 版的安装方法请参考这里。 要在仓库中找到 CUBA 7.2.0 BETA版,请在项目创建向导或项目属性窗口中选择 “Show unstable versions” 复选框。 如果你的项目使用了 REST API 扩展,请在 build.gradle 中手动将其版本更新为 7.2.0.BETA1 : dependencies { appComponent('com.haulmont.cuba:cuba-global:$cubaVersion') appComponent('com.haulmont.addon.restapi:restapi-global:7.2.0.BETA1') } 我们正在测试新版框架及相关扩展组件,并对文档进行完善。如果你也可以使用 Beta 版本,并向我们反馈问题,我们将不胜感激。 我们期待你的反馈!

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

CUBA Studio 13 Beta 版发布 - 企业级应用快速开发平台

大家好, 我们发布了 CUBA Studio 13.0 的 BETA 版。 这个版本中有以下变化值得关注: 对界面设计器进行了重新布局 我们重新对界面设计器的布局进行了设计,以实现以下目标: 更有效地利用IDE的窗口空间 在XML描述和布局预览之间方便地切换 可以让经验丰富的开发人员在查看和编辑XML代码时使用设计器的功能 为此,我们进行了以下更改: 1. 设计器面板成为了独立的 IDE 工具窗口(tool window)。 与以前一样,组件树保留在IDE的右上角 组件工具箱显示在右下角 组件检查器显示在左下角,并包含“属性(Properties )”和“处理程序(Handlers )”选项卡。 当在编辑器中打开界面描述文件时,这些工具窗口会自动显示出来。在编辑器中切换界面描述文件时,工具窗口的内容会自动更新。有时,当打开其他 IDE工具窗口(例如Gradle、Persistence等)时,设计器的面板会隐藏起来,可以通过单击IDE窗口左右两侧的相应按钮来重新打开它们。 对于喜欢旧版设计器布局的用户,我们保留了在右下角显示组件检查器的功能。要将此面板移至右侧,请单击面板标题中的“Move to Right Bottom”按钮。 2. 现在,布局预览面板可与界面描述源码共享编辑器空间 原先的带有“Text”和“Designer”两个选项卡界面设计器已经成为过去。现在界面描述面板的右上角有四个用来切换预览显示方式的按钮: Editor only – 编辑器中仅显示源代码 Editor and Preview - 编辑器空间被拆分为左右两部分,一部分显示源代码,一部分用于预览界面布局 Preview only - 编辑器中仅显示预览(类似于旧的界面设计器布局) Preview in Window - 在窗口中预览,源代码显示在编辑器中,而预览显示在单独的窗口中,可以将其移动到另一个显示器 3. 编辑XML代码并或与编辑器交互时,设计器面板会处于活动状态 经验丰富的开发人员,一般会通过直接编辑XML源代码来修改界面,现在在编辑XML代码时可以利用设计器的一些功能: 在编辑器中光标从一个XML标记移动到另一个XML标记时,在“组件树(Component Hierarchy )”和“组件检查器(Component Inspector)”面板中会选中相应的组件 在 “组件树(Component Hierarchy)” 面板中点击组件节点,会将光标移动到相应的XML标记 当在编辑器中仅显示源代码时,也可以通过从组件工具箱拖拽组件到组件树来创建新的组件,在“检查器(Component Inspector)” 面板中对组件进行重新排序或编辑组件属性后,源代码也会立即作出对应的修改。 界面设计器- 现在可以在组件树中显示表格列和操作 现在,Table(和 DataGrid)的列和操作会显示在“界面设计器”的“组件树”树中,这样可以使我们可以摆脱过多的模式对话框。现在,可以直接在 “组件检查器(Component Inspector)” 面板中查看、编辑列和操作的属性以及配置事件处理器。 添加新的表格列或操作也会变得更加容易。选择表格、表格列或操作后,组件检查器将显示 “ +add” 按钮。点此按钮,可以将一个或多个列或操作添加到表中。 界面设计器-组件创建向导对话框 向界面添加组件、数据容器和操作比以前更加令人感觉轻松。我们针对以下界面元素引入了向导对话框: Data containers-数据容器 Tables and grids - 表格和网格 Table column -表格列 Table action - 表格操作 Form field -表单字段 当在界面上添加上述组件时,将出现一个对话框,提示填写一些重要的属性。例如,在将DataGrid添加到界面时,可以选择现有的或创建新的数据容器、指定组件ID并选择要添加到表中的一组标准操作和按钮。 项目向导的改进 CUBA项目向导进行了增强。我们在各步骤之间重新安排了要填写的要素,并给向导添加了更多字段: Module prefix - 模块前缀 Supported programming languages - 支持的编程语言 Locales - 本地化 Main data store properties -主数据源属性 CUBA 应用程序配置现在支持JVM选项和环境变量 “CUBA Application ” 运行配置中添加了两个设置:命令行参数和环境变量。这些设置将应用于调试模式下运行CUBA应用程序的Tomcat进程。例如,通过指定命令行参数,可以设置非默认时区:“-Duser.timezone = Europe / London”,或为应用程序服务器增加内存:“ -Xmx1500m”。 Kotlin支持(CUBA 7.2) Studio 13完全支持Kotlin作为编程语言。可以在项目创建向导中选择 Kotlin 作为项目的编程语言。 CUBA项目的所有元素:实体、界面和服务都可以使用 Kotlin 生成。 Studio 可视化设计器、智能自动完成、检查和热部署也支持Kotlin语言。 此功能在基于CUBA 7.2+的项目中可用,CUBA 7.2的测试版即将发布。 新的登录界面模板(CUBA 7.2) 添加了具有新的布局和设计的登录界面模板。有关新登录界面外观的示例可在这里找到:https://github.com/cuba-platform/cuba/issues/2455。 要给项目添加新的登录界面,请在 “New -> Screen”中选择 “Login screen with branding image” 模板。 新的界面模板可用于基于CUBA 7.2+的项目,CUBA 7.2的测试版即将发布。 Beta 版测试 我们现在正在测试新的Studio版本。 如果你也能体验 beta 版本,并给我们反馈问题,我们将不胜感激。 13.0. BETA 版本已发布到 JetBrains 插件存储库中的一个独立的插件通道。 要尝试Beta版,需要执行以下操作: 打开 “Settings -> Plugins ” 对话框 单击图标,然后选择 “Manage Plugin Repositories” 单击 “+” ,然后在“Repository URL ”字段中输入以下内容:https://plugins.jetbrains.com/plugins/beta/list 切换到 “Marketplace” 选项卡。应该马上能看到 CUBA 插件请求更新到 13.0.BETA 版本 单击 “Update” 如果需要返回到稳定版本,请执行以下操作: 打开 “Settings -> Plugins ” 对话框 卸载CUBA插件 单击图标,然后选择 “Manage Plugin Repositories” 从列表中删除 “beta” 存储库 再次安装CUBA插件,它将来自稳定版的插件通道。 参考消息:https://forum.cuba-platform.cn/t/topic/919

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

带你快速了解Java锁中的公平锁与非公平锁

前言 Java语言中有许多原生线程安全的数据结构,比如ArrayBlockingQueue、CopyOnWriteArrayList、LinkedBlockingQueue,它们线程安全的实现方式并非通过synchronized关键字,而是通过java.util.concurrent.locks.ReentrantLock来实现。 锁的底层实现 无论什么语言在操作系统层面锁的操作都会变成系统调用(System Call),以 Linux 为例,就是 futex 函数,可以把它理解为两个函数:futex_wait(s),对变量 s 加锁;futex_wake(s)释放 s 上的锁,唤醒其他线程。在ReentrantLock中很明显可以看到其中同步包括两种,分别是公平的FairSync和非公平的NonfairSync。公平锁的作用就是严格按照线程启动的顺序来执行的,不允许其他线程插队执行的;而非公平锁是允许插队的。默认情况下ReentrantLock是通过非公平锁来进行同步的,包括synchronized关键字都是如此,因为这样性能会更好。因为从线程进入了RUNNABLE状态,可以执行开始,到实际线程执行是要比较久的时间的。 而且,在一个锁释放之后,其他的线程会需要重新来获取锁。其中经历了持有锁的线程释放锁,其他线程从挂起恢复到RUNNABLE状态,其他线程请求锁,获得锁,线程执行,这一系列步骤。如果这个时候,存在一个线程直接请求锁,可能就避开挂起到恢复RUNNABLE状态的这段消耗,所以性能更优化。 /** * Creates an instance of {@code ReentrantLock}. * This is equivalent to using {@code ReentrantLock(false)}. */ public ReentrantLock() { sync = new NonfairSync(); } 默认状态,使用的ReentrantLock()就是非公平锁。再参考如下代码,我们知道ReentrantLock的获取锁的操作是通过装饰模式代理给sync的。 /** * Acquires the lock. * * <p>Acquires the lock if it is not held by another thread and returns * immediately, setting the lock hold count to one. * * <p>If the current thread already holds the lock then the hold * count is incremented by one and the method returns immediately. * * <p>If the lock is held by another thread then the * current thread becomes disabled for thread scheduling * purposes and lies dormant until the lock has been acquired, * at which time the lock hold count is set to one. */ public void lock() { sync.lock(); } 下面参考一下FairSync和NonfairSync对lock方法的实现: /** * Sync object for non-fair locks */ static final class NonfairSync extends Sync { /** * Performs lock. Try immediate barge, backing up to normal * acquire on failure. */ final void lock() { if (compareAndSetState(0, 1)) setExclusiveOwnerThread(Thread.currentThread()); else acquire(1); } } /** * Sync object for fair locks */ static final class FairSync extends Sync { final void lock() { acquire(1); } } 当使用非公平锁的时候,会立刻尝试配置状态,成功了就会插队执行,失败了就会和公平锁的机制一样,调用acquire()方法,以排他的方式来获取锁,成功了立刻返回,否则将线程加入队列,知道成功调用为止。欢迎大家关注我的公种浩【程序员追风】,2019年多家公司java面试题整理了1000多道400多页pdf文档,文章都会在里面更新,整理的资料也会放在里面。 总结 上锁的过程本身也是有时间开销的,如果操作资源的时间比上锁的时间还短建议使用非公平锁可以提高系统的吞吐率;否则就老老实实的用公平锁。 最后 欢迎大家一起交流,喜欢文章记得点个赞哟,感谢支持!

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

Alibaba Arthas 3.1.5版本支持火焰图,快速定位应用热点

Arthas是Alibaba开源的Java诊断工具,深受开发者喜爱。 Gitee: https://gitee.com/arthas/arthas Github: https://github.com/alibaba/arthas 文档:https://alibaba.github.io/arthas Arthas 3.1.5版本带来下面全新的特性: 开箱即用的Profiler/火焰图功能 grep命令支持更丰富的选项 monitor/tt/trace等命令提供更精确的时间统计 telnet/http协议共用3658端口 Profiler/Frame Graph/火焰图 火焰图的威名相信大家都有所耳闻,但可能因为使用比较复杂,所以望而止步。 在新版本的Arthas里集成了 async-profiler ,使用 profiler命令就可以很方便地生成火焰图,并且可以在浏览器里直接查看。 profiler命令wiki: https://alibaba.github.io/arthas/profiler.html profiler命令基本运行结构是 profiler action [actionArg] 。下面介绍如何使用。 启动profiler $ profiler start Started [cpu] profiling 默认情况下,生成的是cpu的火焰图,即event为`cpu`。可以用`--event`参数来指定。 获取已采集的sample的数量 $ profiler getSamples 23 查看profiler状态 $ profiler status [cpu] profiling is running for 4 seconds 可以查看当前profiler在采样哪种`event`和采样时间。 生成svg格式结果 $ profiler stop profiler output file: /tmp/demo/arthas-output/20191125-135546.svg OK 默认情况下,生成的结果保存到应用的`工作目录`下的`arthas-output`目录里。 通过浏览器查看arthas-output下面的profiler结果 默认情况下,arthas使用3658端口,则可以打开: http://localhost:3658/arthas-output/查看到`arthas-output`目录下面的profiler结果: 点击可以查看具体的结果: 如果是chrome浏览器,可能需要多次刷新。 grep命令支持更丰富的选项 标准的linux grep命令支持丰富的选项,可以很方便地定位结果的上下文等。 新版本的`grep`命令支持更多标准的选项,下面是一些例子: sysprop | grep java sysprop | grep java -n sysenv | grep -v JAVA sysenv | grep -e "(?i)(JAVA|sun)" -m 3 -C 2 sysenv | grep JAVA -A2 -B3 thread | grep -m 10 -e "TIMED_WAITING|WAITING" 感谢社区里 @qxo 的贡献。 telnet/http协议共用3658端口 默认情况下,Arthas的Telnet端口是3658,HTTP端口是8563,这个常常让用户迷惑。在新版本里,在3658端口同时支持Telnet/HTTP协议。 在浏览器里访问 http://localhost:3658/ 也可以访问到Web Console了。 在后续的版本里,考虑默认只侦听 3658端口,减少用户的配置项。 monitor/tt/trace等命令提供更精确的时间统计 以前Arthas被诟病比较多的一个问题是,monitor/tt/trace等命令时间统计误差大。因为以前只使用了一个int来保存时间,所以不精确。 在新版本里,改用一个高效的stack来保存数据,时间的准确度大大提升,欢迎大家反馈效果。 感谢社区里 @huangjIT 的贡献。 总结 总之,3.1.5版本的Arthas引入了开箱即用的Profiler/火焰图功能,欢迎大家使用反馈。 Release Note: https://github.com/alibaba/arthas/releases/tag/arthas-all-3.1.5 火焰图的一个参考文章:https://openresty.org/posts/dynamic-tracing/ 最后,Arthas 正在参加2019年度最受欢迎开源中国软件评选,急需大家宝贵的一票支持!!查看 投票后可以到issue里参与图书抽奖:https://github.com/alibaba/arthas/issues/951

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

每日一博 | 如何快速安全地插入千万条数据

前言 最近有个需求解析一个订单文件,并且说明文件可达到千万条数据,每条数据大概在20个字段左右,每个字段使用逗号分隔,需要尽量在半小时内入库。 思路 1.估算文件大小 因为告诉文件有千万条,同时每条记录大概在20个字段左右,所以可以大致估算一下整个订单文件的大小,方法也很简单使用FileWriter往文件中插入一千万条数据,查看文件大小,经测试大概在1.5G左右; 2.如何批量插入 由上可知文件比较大,一次性读取内存肯定不行,方法是每次从当前订单文件中截取一部分数据,然后进行批量插入,如何批次插入可以使用insert(...)values(...),(...)的方式,经测试这种方式效率还是挺高的; 3.数据的完整性 截取数据的时候需要注意,需要保证数据的完整性,每条记录最后都是一个换行符,需要根据这个标识保证每次截取都是整条数,不要出现半条数据这种情况; 4.数据库是否支持批次数据 因为需要进行批次数据的插入,数据库是否支持大量数据写入,比如这边使用的mysql,可以通过设置max_allowed_packet来保证批次提交的数据量; 5.中途出错的情况 因为是大文件解析,如果中途出现错误,比如数据刚好插入到900w的时候,数据库连接失败,这种情况不可能重新来插一遍,所有需要记录每次插入数据的位置,并且需要保证和批次插入的数据在同一个事务中,这样恢复之后可以从记录的位置开始继续插入。 实现 1.准备数据表 这里需要准备两张表分别是:订单状态位置信息表,订单表; CREATE TABLE `file_analysis` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `file_type` varchar(255) NOT NULL COMMENT '文件类型 01:类型1,02:类型2', `file_name` varchar(255) NOT NULL COMMENT '文件名称', `file_path` varchar(255) NOT NULL COMMENT '文件路径', `status` varchar(255) NOT NULL COMMENT '文件状态 0初始化;1成功;2失败:3处理中', `position` bigint(20) NOT NULL COMMENT '上一次处理完成的位置', `crt_time` datetime NOT NULL COMMENT '创建时间', `upd_time` datetime NOT NULL COMMENT '更新时间', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 CREATE TABLE `file_order` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `file_id` bigint(20) DEFAULT NULL, `field1` varchar(255) DEFAULT NULL, `field2` varchar(255) DEFAULT NULL, `field3` varchar(255) DEFAULT NULL, `field4` varchar(255) DEFAULT NULL, `field5` varchar(255) DEFAULT NULL, `field6` varchar(255) DEFAULT NULL, `field7` varchar(255) DEFAULT NULL, `field8` varchar(255) DEFAULT NULL, `field9` varchar(255) DEFAULT NULL, `field10` varchar(255) DEFAULT NULL, `field11` varchar(255) DEFAULT NULL, `field12` varchar(255) DEFAULT NULL, `field13` varchar(255) DEFAULT NULL, `field14` varchar(255) DEFAULT NULL, `field15` varchar(255) DEFAULT NULL, `field16` varchar(255) DEFAULT NULL, `field17` varchar(255) DEFAULT NULL, `field18` varchar(255) DEFAULT NULL, `crt_time` datetime NOT NULL COMMENT '创建时间', `upd_time` datetime NOT NULL COMMENT '更新时间', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=10000024 DEFAULT CHARSET=utf8 2.配置数据库包大小 mysql> show VARIABLES like '%max_allowed_packet%'; +--------------------------+------------+ | Variable_name | Value | +--------------------------+------------+ | max_allowed_packet | 1048576 | | slave_max_allowed_packet | 1073741824 | +--------------------------+------------+ 2 rows in set mysql> set global max_allowed_packet = 1024*1024*10; Query OK, 0 rows affected 通过设置max_allowed_packet,保证数据库能够接收批次插入的数据包大小;不然会出现如下错误: Caused by: com.mysql.jdbc.PacketTooBigException: Packet for query is too large (4980577 > 1048576). You can change this value on the server by setting the max_allowed_packet' variable. at com.mysql.jdbc.MysqlIO.send(MysqlIO.java:3915) at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:2598) at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2778) at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2834) 3.准备测试数据 public static void main(String[] args) throws IOException { FileWriter out = new FileWriter(new File("D://xxxxxxx//orders.txt")); for (int i = 0; i < 10000000; i++) { out.write( "vaule1,vaule2,vaule3,vaule4,vaule5,vaule6,vaule7,vaule8,vaule9,vaule10,vaule11,vaule12,vaule13,vaule14,vaule15,vaule16,vaule17,vaule18"); out.write(System.getProperty("line.separator")); } out.close(); } 使用FileWriter遍历往一个文件里插入1000w条数据即可,这个速度还是很快的,不要忘了在每条数据的后面添加换行符(\n\r); 4.截取数据的完整性 除了需要设置每次读取文件的大小,同时还需要设置一个参数,用来每次获取一小部分数据,从这小部分数据中获取换行符(\n\r),如果获取不到一直累加直接获取为止,这个值设置大小大致同每条数据的大小差不多合适,部分实现如下: ByteBuffer byteBuffer = ByteBuffer.allocate(buffSize); // 申请一个缓存区 long endPosition = batchFileSize + startPosition - buffSize;// 子文件结束位置 long startTime, endTime; for (int i = 0; i < count; i++) { startTime = System.currentTimeMillis(); if (i + 1 != count) { int read = inputChannel.read(byteBuffer, endPosition);// 读取数据 readW: while (read != -1) { byteBuffer.flip();// 切换读模式 byte[] array = byteBuffer.array(); for (int j = 0; j < array.length; j++) { byte b = array[j]; if (b == 10 || b == 13) { // 判断\n\r endPosition += j; break readW; } } endPosition += buffSize; byteBuffer.clear(); // 重置缓存块指针 read = inputChannel.read(byteBuffer, endPosition); } } else { endPosition = fileSize; // 最后一个文件直接指向文件末尾 } ...省略,更多可以查看Github完整代码... } 如上代码所示开辟了一个缓冲区,根据每行数据大小来定大概在200字节左右,然后通过遍历查找换行符(\n\r),找到以后将当前的位置加到之前的结束位置上,保证了数据的完整性; 5.批次插入数据 通过insert(...)values(...),(...)的方式批次插入数据,部分代码如下: // 保存订单和解析位置保证在一个事务中 SqlSession session = sqlSessionFactory.openSession(); try { long startTime = System.currentTimeMillis(); FielAnalysisMapper fielAnalysisMapper = session.getMapper(FielAnalysisMapper.class); FileOrderMapper fileOrderMapper = session.getMapper(FileOrderMapper.class); fileOrderMapper.batchInsert(orderList); // 更新上次解析到的位置,同时指定更新时间 fileAnalysis.setPosition(endPosition + 1); fileAnalysis.setStatus("3"); fileAnalysis.setUpdTime(new Date()); fielAnalysisMapper.updateFileAnalysis(fileAnalysis); session.commit(); long endTime = System.currentTimeMillis(); System.out.println("===插入数据花费:" + (endTime - startTime) + "ms==="); } catch (Exception e) { session.rollback(); } finally { session.close(); } ...省略,更多可以查看Github完整代码... 如上代码在一个事务中同时保存批次订单数据和文件解析位置信息,batchInsert通过使用mybatis的<foreach>标签来遍历订单列表,生成values数据; 总结 以上展示了部分代码,完整的代码可以查看Github地址中的batchInsert模块,本地设置每次截取的文件大小为2M,经测试1000w条数据(大小1.5G左右)插入mysql数据库中,大概花费时间在20分钟左右,当然可以通过设置截取的文件大小,花费的时间也会相应的改变。 完整代码 Github

资源下载

更多资源
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等操作系统。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册