首页 文章 精选 留言 我的

精选列表

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

D 语言/DLang 2.096.0 发布,增强跨平台能力!

DMD 2.096.0 正式发布更新,DMD 是 D语言官方推出的编译器,此版本包含了 17 项主要变更,同时修复 81 个已知bug。相信过几天 LDC 也会跟进到本次大更新!这个版本有 54 个开发者进行参与,非常感谢他们为 DLang 的发展做出的贡献。 编译器变更 x86_64 Posix 平台下的 D ABI 有所更改 新增类型:__c_complex_float、__c_complex_double 和 __c_complex_real 不再支持构造函数复制和块复制(postblit) DMD 的 JSON 输出现在会包含保护级成员 DMD 的 JSON 输出现在会区分处理模块的构造方法和析构方法(包含有无shared的情形) 局部模板不再支持接收通过别名(alias)传入的局部符号 增强了 C++ 头文件的生成功能 新增编译器开关:-gdwarf=<version> 新增 __traits(getVisibility, Sym) 来替代 getProtection 无参的 synchronized 语句现在会使用运行时分配的互斥量 允许使用更短形式的函数实现(单一表达式函数) 运行时变更 移除了 druntime 里的参数选项 callStructDtorsDuringGC 在 mount 模块里,移除了与 FreeBSD 相关的 statvfs 声明 新增体验功能:基于 backtrace 输出的 llvm-libunwind 库变更 弃用 std.math 模块里的 approxEqual 方法 Dub变更 支持更多 DMD 的连接器参数 VisualD 的工程里允许使用 copyFiles 更多参考 DMD 2.096.0 – Changelog

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

Android 快速集成文档校正能力 超简单

前言 在之前的《超简单集成华为HMS ML Kit文本识别SDK,一键实现账单号自动录入》文章中,我们给大家介绍了华为HMS ML Kit文本识别技术如何通过拍照自动识别照片中的文本信息。那么有的小伙伴可能会问,如果拍照时不是正对着文本拍摄,拍出来的照片是歪斜的,那么还能准确识别文本吗?当然可以啦。HMS ML Kit文档校正技术可以自动识别文档位置,校正拍摄角度,并且支持用户自定义边界点位置,即使在倾斜角度也能够拍摄出文档的正面图像。 应用场景 文档校正技术在生活中有很多的应用场景。比如说在拍摄纸质文档时,相机处于倾斜的角度,导致阅读文档非常不方便。使用文档校正技术可以把文档调整到正对的视角,这样阅读起来就顺利多了。 再比如在记录卡证信息时,使用文档校正技术,不需要调整到正对卡证的视角,也可以拍摄出卡证的正面照片。 另外,在行程中因为身处于倾斜位置,道路旁的路牌难以准确识别,这时可以通过文档校正技术拍摄到路牌正面图片。 怎么样,是不是很方便呢?那我们接下来详细给大家介绍安卓如何快速集成文档校正技术。 开发实战 详细的准备步骤可以参考华为开发者联盟: https://developer.huawei.com/consumer/cn/doc/development/HMS-Guides/ml-process-4 这里列举关键的开发步骤。 1.1 项目级gradle里配置Maven仓地址 buildscript { repositories { ... maven {url 'https://developer.huawei.com/repo/'} } } dependencies { ... classpath 'com.huawei.agconnect:agcp:1.3.1.300' } allprojects { repositories { ... maven {url 'https://developer.huawei.com/repo/'} } } 1.2 应用级gradle里配置SDK依赖 dependencies{ // 引入基础SDK implementation 'com.huawei.hms:ml-computer-vision-documentskew:2.0.2.300' // 引入文档检测/校正模型包 implementation 'com.huawei.hms:ml-computer-vision-documentskew-model:2.0.2.300' } 1.3 在文件头添加配置 apply plugin: 'com.huawei.agconnect' apply plugin: 'com.android.application' 1.4 添加如下语句到AndroidManifest.xml文件中,自动更新机器学习模型到设备 <meta-data android:name="com.huawei.hms.ml.DEPENDENCY" android:value= "dsc"/> 1.5 申请摄像机权限和读本地图片权限 <uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> 2. 代码开发 2.1 创建文本框检测/校正分析器 MLDocumentSkewCorrectionAnalyzerSetting setting = new MLDocumentSkewCorrectionAnalyzerSetting.Factory().create(); MLDocumentSkewCorrectionAnalyzer analyzer = MLDocumentSkewCorrectionAnalyzerFactory.getInstance().getDocumentSkewCorrectionAnalyzer(setting); 2.2 通过android.graphics.Bitmap创建MLFrame对象用于分析器检测图片,支持的图片格式包括:jpg/jpeg/png,建议图片尺寸不小于320320像素,不大于19201920像素。 MLFrame frame = MLFrame.fromBitmap(bitmap); 2.3 调用asyncDocumentSkewDetect异步方法或analyseFrame同步方法进行文本框的检测。当返回码是MLDocumentSkewCorrectionConstant.SUCCESS时,将会返回文本框的四个顶点的坐标值,该坐标值是相对于传入图像的坐标,若与设备坐标不一致,需调用者进行转换;否则,返回的数据没有意义。 // asyncDocumentSkewDetect异步调用。 Task<MLDocumentSkewDetectResult> detectTask = analyzer.asyncDocumentSkewDetect(mlFrame); detectTask.addOnSuccessListener(new OnSuccessListener<MLDocumentSkewDetectResult>() { @Override public void onSuccess(MLDocumentSkewDetectResult detectResult) { // 检测成功。 } }).addOnFailureListener(new OnFailureListener() { @Override public void onFailure(Exception e) { // 检测失败。 } }) // analyseFrame同步调用。 SparseArray<MLDocumentSkewDetectResult> detect = analyzer.analyseFrame(mlFrame); if (detect != null && detect.get(0).getResultCode() == MLDocumentSkewCorrectionConstant.SUCCESS) { // 检测成功。 } else { // 检测失败。 } 2.4 检测成功后,分别获取文本框四个顶点的坐标数据,然后以左上角为起点,按顺时针方向,分别把左上角、右上角、右下角、左下角加入到列表(List<Point>)中,最后构建MLDocumentSkewCorrectionCoordinateInput对象。 2.4.1 如果使用analyseFrame同步调用,先获取到检测结果,如下所示(使用asyncDocumentSkewDetect异步调用可忽略此步骤直接进行步骤2.4.2): MLDocumentSkewDetectResult detectResult = detect.get(0); 2.4.2 获取文本框四个顶点的坐标数据并构建MLDocumentSkewCorrectionCoordinateInput对象: Point leftTop = detectResult.getLeftTopPosition(); Point rightTop = detectResult.getRightTopPosition(); Point leftBottom = detectResult.getLeftBottomPosition(); Point rightBottom = detectResult.getRightBottomPosition(); List<Point> coordinates = new ArrayList<>(); coordinates.add(leftTop); coordinates.add(rightTop); coordinates.add(rightBottom); coordinates.add(leftBottom); MLDocumentSkewCorrectionCoordinateInput coordinateData = new MLDocumentSkewCorrectionCoordinateInput(coordinates); 2.5 调用asyncDocumentSkewCorrect异步方法或syncDocumentSkewCorrect同步方法进行文本框的校正。 // asyncDocumentSkewCorrect异步调用。 Task<MLDocumentSkewCorrectionResult> correctionTask = analyzer.asyncDocumentSkewCorrect(mlFrame, coordinateData); correctionTask.addOnSuccessListener(new OnSuccessListener<MLDocumentSkewCorrectionResult>() { @Override public void onSuccess(MLDocumentSkewCorrectionResult refineResult) { // 检测成功。 } }).addOnFailureListener(new OnFailureListener() { @Override public void onFailure(Exception e) { // 检测失败。 } }); // syncDocumentSkewCorrect同步调用。 SparseArray<MLDocumentSkewCorrectionResult> correct= analyzer.syncDocumentSkewCorrect(mlFrame, coordinateData); if (correct != null && correct.get(0).getResultCode() == MLDocumentSkewCorrectionConstant.SUCCESS) { // 校正成功。 } else { // 校正失败。 } 2.6 检测完成,停止分析器,释放检测资源。 if (analyzer != null) { analyzer.stop(); } Demo效果 下面这个demo展示了在倾斜角度扫描文档,文档校正技术可以把文档调整到正对视角。效果是不是很棒? 文档校正技术还可以辅助文档识别技术,将倾斜的文档调整到正面视角,快速实现从纸质文件到电子文件的转化,大幅度提升信息的录入效率。 Github源码 https://github.com/HMS-Core/hms-ml-demo/blob/master/MLKit-Sample/module-text/src/main/java/com/mlkit/sample/activity/DocumentSkewCorretionActivity.java 更详细的开发指南参考华为开发者联盟官网 https://developer.huawei.com/consumer/cn/hms/huawei-mlkit 欲了解更多详情,请参阅: 华为开发者联盟官网:https://developer.huawei.com/consumer/cn/hms 获取开发指导文档:https://developer.huawei.com/consumer/cn/doc/development 参与开发者讨论请到Reddit社区:https://www.reddit.com/r/HMSCore/ 下载demo和示例代码请到Github:https://github.com/HMS-Core 解决集成问题请到Stack Overflow:https://stackoverflow.com/questions/tagged/huawei-mobile-services?tab=Newest 文章来源:https://developer.huawei.com/consumer/cn/forum/topicview?tid=0202344452930050418&fid=18 作者:留下落叶

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

JVM优化-Java架构师能力提升必学

想要成为一名出色的Java架构师,必须要彻底了解Java的一个重要的特点那就JVM 动力节点Java学院寄语 前些天面试了阿里的实习生,问到关于Dalvik虚拟机能不能执行class文件,我当时的回答是不能,但是它执行的是class转换的dex文件。 当面试官继续问,为什么不能执行class文件时,我却只能回答Dalvik虚拟机内部的优化原因,却不能正确回答具体的原因。 其实周志明的这本书就有回答:Dakvik并不是一个Java虚拟机,它没有遵循Java虚拟机规范,不能执行Java的class文件,使用的是寄存器架构而不是JVM中常见的栈架构,但是它与Java又有着千丝万缕的关系,它执行的dex文件可以通过class文件转化而来。 其实在本科期间,就有接触过《深入理解Java虚拟机》,但是一直以来都没去仔细研读,现在回头想想实在是觉得可惜!研一期间花了不少时间研读,现在准备找工作了,发现好多内容看了又忘。索性写一篇文章,把这本书的知识点做一个总结。当然了,如果你想看比较详细的内容,可以翻看《深入理解Java虚拟机》。 JVM内存区域我们在编写程序时,经常会遇到OOM(out of Memory)以及内存泄漏等问题。为了避免出现这些问题,我们首先必须对JVM的内存划分有个具体的认识。JVM将内存主要划分为:方法区、虚拟机栈、本地方法栈、堆、程序计数器。JVM运行时数据区如下: 程序计数器程序计数器是线程私有的区域,很好理解嘛~,每个线程当然得有个计数器记录当前执行到那个指令。占用的内存空间小,可以把它看成是当前线程所执行的字节码的行号指示器。如果线程在执行Java方法,这个计数器记录的是正在执行的虚拟机字节码指令地址;如果执行的是Native方法,这个计数器的值为空(Undefined)。此内存区域是唯一一个在Java虚拟机规范中没有规定任何OutOfMemoryError情况的区域。Java虚拟机栈与程序计数器一样,Java虚拟机栈也是线程私有的。其生命周期与线程相同。如何理解虚拟机栈呢?本质上来讲,就是个栈。里面存放的元素叫栈帧,栈帧好像很复杂的样子,其实它很简单!它里面存放的是一个函数的上下文,具体存放的是执行的函数的一些数据。执行的函数需要的数据无非就是局部变量表(保存函数内部的变量)、操作数栈(执行引擎计算时需要),方法出口等等。执行引擎每调用一个函数时,就为这个函数创建一个栈帧,并加入虚拟机栈。换个角度理解,每个函数从调用到执行结束,其实是对应一个栈帧的入栈和出栈。注意这个区域可能出现的两种异常:一种是StackOverflowError,当前线程请求的栈深度大于虚拟机所允许的深度时,会抛出这个异常。制造这种异常很简单:将一个函数反复递归自己,最终会出现栈溢出错误(StackOverflowError)。另一种异常是OutOfMemoryError异常,当虚拟机栈可以动态扩展时(当前大部分虚拟机都可以),如果无法申请足够多的内存就会抛出OutOfMemoryError,如何制作虚拟机栈OOM呢,参考一下代码: 1.publicvoidstackLeakByThread(){2.while(true){3.newThread(){4.publicvoidrun(){5.while(true){6.}7.}8.}.start()9.}10.} ``这段代码有风险,可能会导致操作系统假死,请谨慎使用~~~本地方法栈本地方法栈与虚拟机栈所发挥的作用很相似,他们的区别在于虚拟机栈为执行Java代码方法服务,而本地方法栈是为Native方法服务。与虚拟机栈一样,本地方法栈也会抛出StackOverflowError和OutOfMemoryError异常。 Java堆Java堆可以说是虚拟机中最大一块内存了。它是所有线程所共享的内存区域,几乎所有的实例对象都是在这块区域中存放。当然,睡着JIT编译器的发展,所有对象在堆上分配渐渐变得不那么“绝对”了。Java堆是垃圾收集器管理的主要区域。由于现在的收集器基本上采用的都是分代收集算法,所有Java堆可以细分为:新生代和老年代。在细致分就是把新生代分为:Eden空间、From Survivor空间、To Survivor空间。当堆无法再扩展时,会抛出OutOfMemoryError异常。方法区方法区存放的是类信息、常量、静态变量等。方法区是各个线程共享区域,很容易理解,我们在写Java代码时,每个线程度可以访问同一个类的静态变量对象。由于使用反射机制的原因,虚拟机很难推测那个类信息不再使用,因此这块区域的回收很难。另外,对这块区域主要是针对常量池回收,值得注意的是JDK1.7已经把常量池转移到堆里面了。同样,当方法区无法满足内存分配需求时,会抛出OutOfMemoryError。制造方法区内存溢出,注意,必须在JDK1.6及之前版本才会导致方法区溢出,原因后面解释,执行之前,可以把虚拟机的参数-XXpermSize和-XX:MaxPermSize限制方法区大小。1.Listlist=newArrayList();2.inti=0;3.while(true){4.list.add(String.valueOf(i).intern());5.}运行后会抛出java.lang.OutOfMemoryError:PermGen space异常。解释一下,String的intern()函数作用是如果当前的字符串在常量池中不存在,则放入到常量池中。上面的代码不断将字符串添加到常量池,最终肯定会导致内存不足,抛出方法区的OOM。下面解释一下,为什么必须将上面的代码在JDK1.6之前运行。我们前面提到,JDK1.7后,把常量池放入到堆空间中,这导致intern()函数的功能不同,具体怎么个不同法,且看看下面代码:1.Stringstr1=newStringBuilder("hua").append("chao").toString();2.System.out.println(str1.intern()==str1);3.Stringstr2=newStringBuilder("ja").append("va").toString();4.System.out.println(str2.intern()==str2);这段代码在JDK1.6和JDK1.7运行的结果不同。JDK1.6结果是:false,false ,JDK1.7结果是true, false。原因是:JDK1.6中,intern()方法会吧首次遇到的字符串实例复制到常量池中,返回的也是常量池中的字符串的引用,而StringBuilder创建的字符串实例是在堆上面,所以必然不是同一个引用,返回false。在JDK1.7中,intern不再复制实例,常量池中只保存首次出现的实例的引用,因此intern()返回的引用和由StringBuilder创建的字符串实例是同一个。为什么对str2比较返回的是false呢?这是因为,JVM中内部在加载类的时候,就已经有"java"这个字符串,不符合“首次出现”的原则,因此返回false。垃圾回收(GC)JVM的垃圾回收机制中,判断一个对象是否死亡,并不是根据是否还有对象对其有引用,而是通过可达性分析。对象之间的引用可以抽象成树形结构,通过树根(GC Roots)作为起点,从这些树根往下搜索,搜索走过的链称为引用链,当一个对象到GC Roots没有任何引用链相连时,则证明这个对象是不可用的,该对象会被判定为可回收的对象。那么那些对象可作为GC Roots呢?主要有以下几种:1.虚拟机栈(栈帧中的本地变量表)中引用的对象。2.方法区中类静态属性引用的对象。3.方法区中常量引用的对象4.本地方法栈中JNI(即一般说的Native方法)引用的对象。另外,Java还提供了软引用和弱引用,这两个引用是可以随时被虚拟机回收的对象,我们将一些比较占内存但是又可能后面用的对象,比如Bitmap对象,可以声明为软引用货弱引用。但是注意一点,每次使用这个对象时候,需要显示判断一下是否为null,以免出错。 三种常见的垃圾收集算法1.标记-清除算法首先,通过可达性分析将可回收的对象进行标记,标记后再统一回收所有被标记的对象,标记过程其实就是可达性分析的过程。这种方法有2个不足点:效率问题,标记和清除两个过程的效率都不高;另一个是空间问题,标记清除之后会产生大量的不连续的内存碎片。2.复制算法为了解决效率问题,复制算法是将内存分为大小相同的两块,每次只使用其中一块。当这块内存用完了,就将还存活的对象复制到另一块内存上面。然后再把已经使用过的内存一次清理掉。这使得每次只对半个区域进行垃圾回收,内存分配时也不用考虑内存碎片情况。但是,这代价实在是让人无法接受,需要牺牲一般的内存空间。研究发现,大部分对象都是“朝生夕死”,所以不需要安装1:1比例划分内存空间,而是将内存分为一块较大的Eden空间和两块较小的Survivor空间,每次使用Eden空间和一块Survivor空间,默认比例为Eden:Survivor=8:1.新生代区域就是这么划分,每次实例在Eden和一块Survivor中分配,回收时,将存活的对象复制到剩下的另一块Survivor。这样只有10%的内存会被浪费,但是带来的效率却很高。当剩下的Survivor内存不足时,可以去老年代内存进行分配担保。如何理解分配担保呢,其实就是,内存不足时,去老年代内存空间分配,然后等新生代内存缓过来了之后,把内存归还给老年代,保持新生代中的Eden:Survivor=8:1.另外,两个Survivor分别有自己的名称:From Survivor、To Survivor。二者身份经常调换,即有时这块内存与Eden一起参与分配,有时是另一块。因为他们之间经常相互复制。3.标记-整理算法标记整理算法很简单,就是先标记需要回收的对象,然后把所有存活的对象移动到内存的一端。这样的好处是避免了内存碎片。类加载机制类从被加载到虚拟机内存开始,到卸载出内存为止,整个生命周期包括:加载、验证、准备、解析、初始化、使用和卸载七个阶段。其中加载、验证、准备、初始化、和卸载这5个阶段的顺序是确定的。而解析阶段不一定:它在某些情况下可以在初始化阶段之后再开始,这是为了支持Java的运行时绑定。关于初始化:JVM规范明确规定,有且只有5中情况必须执行对类的初始化(加载、验证、准备自然再此之前要发生):1.遇到new、getstatic、putstatic、invokestatic,如果类没有初始化,则必须初始化,这几条指令分别是指:new新对象、读取静态变量、设置静态变量,调用静态函数。2.使用java.lang.reflect包的方法对类进行反射调用时,如果类没初始化,则需要初始化3.当初始化一个类时,如果发现父类没有初始化,则需要先触发父类初始化。4.当虚拟机启动时,用户需要制定一个执行的主类(包含main函数的类),虚拟机会先初始化这个类。5.但是用JDK1.7启的动态语言支持时,如果一个MethodHandle实例最后解析的结果是REF_getStatic、REF_putStatic、Ref_invokeStatic的方法句柄时,并且这个方法句柄所对应的类没有进行初始化,则要先触发其初始化。另外要注意的是:通过子类来引用父类的静态字段,不会导致子类初始化:1.publicclassSuperClass{2.publicstaticintvalue=123;3.static{4.System.out.printLn("SuperClassinit!");5.}6.}7.publicclassSubClassextendsSuperClass{8.static{9.System.out.println("SubClassinit!");10.}11.}12.publicclassTest{13.publicstaticvoidmain(String[]args){14.System.out.println(SubClass.value);15.}16.}最后只会打印:SuperClass init!对应静态变量,只有直接定义这个字段的类才会被初始化,因此通过子类类引用父类中定义的静态变量只会触发父类初始化而不会触发子类初始化。通过数组定义来引用类,不会触发此类的初始化:1.publicclassTest{2.publicstaticvoidmain(String[]args){3.SuperClass[]sca=newSuperClass[10];4.}5.}常量会在编译阶段存入调用者的常量池,本质上并没有直接引用到定义常量的类,因此不会触发定义常量的类初始化,示例代码如下:1.publicclassConstClass{2.publicstaticfinalStringHELLO_WORLD="helloworld";3.static{4.System.out.println("ConstClassinit!");5.}6.}7.publicclassTest{8.publicstaticvoidmain(String[]args){9.System.out.print(ConstClass.HELLO_WORLD);10.}11.}上面代码不会出现ConstClass init!加载加载过程主要做以下3件事1.通过一个类的全限定名称来获取此类的二进制流2.强这个字节流所代表的静态存储结构转化为方法区的运行时数据结构3.在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据访问入口。验证这个阶段主要是为了确保Class文件字节流中包含信息符合当前虚拟机的要求,并且不会出现危害虚拟机自身的安全。准备准备阶段是正式为类变量分配内存并设置类变量初始值的阶段,这些变量所使用的内存都在方法区中分配。首先,这个时候分配内存仅仅包括类变量(被static修饰的变量),而不包括实例变量。实例变量会在对象实例化时随着对象一起分配在java堆中。其次这里所说的初始值“通常情况下”是数据类型的零值,假设一个类变量定义为1.publicstaticintvalue=123;那变量value在准备阶段后的初始值是0,而不是123,因为还没有执行任何Java方法,而把value赋值为123是在程序编译后,存放在类构造函数()方法中。解析解析阶段是把虚拟机中常量池的符号引用替换为直接引用的过程。初始化类初始化时类加载的最后一步,前面类加载过程中,除了加载阶段用户可以通过自定义类加载器参与以外,其余动作都是虚拟机主导和控制。到了初始化阶段,才是真正执行类中定义Java程序代码。准备阶段中,变量已经赋过一次系统要求的初始值,而在初始化阶段,根据程序员通过程序制定的主观计划初始化类变量。初始化过程其实是执行类构造器()方法的过程。()方法是由编译器自动收集类中所有类变量的赋值动作和静态语句块中的语句合并产生的。收集的顺序是按照语句在源文件中出现的顺序。静态语句块中只能访问定义在静态语句块之前的变量,定义在它之后的变量可以赋值,但不能访问。如下所示:1.publicclassTest{2.static{3.i=0;4.System.out.print(i);5.}6.staticinti=1;7.}()方法与类构造函数(或者说实例构造器())不同,他不需要显式地调用父类构造器,虚拟机会保证子类的()方法执行之前,父类的()已经执行完毕。类加载器关于自定义类加载器,和双亲委派模型,这里不再提,写了几个小时了,该洗洗睡了~动力节点Java架构师班深度剖析Java底层原理,热门技术深入探讨,前沿技术深入解读,大项目实战重构,从0到1做架构,从全局思维出发,带你把控大型项目中别人忽略的重要细节节点,站在巨人肩膀上学习架构师,带你领会架构师不一样的视野

资源下载

更多资源
腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

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应用均可从中受益。

WebStorm

WebStorm

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

用户登录
用户注册