struts2新特性预览

Struts2与Struts1的对比

Action 类: 
• Struts1要求Action类继承一个抽象基类。Struts1的一个普遍问题是使用抽象类编程而不是接口。 
• Struts 2 Action类可以实现一个Action接口,也可实现其他接口,使可选和定制的服务成为可能。Struts2提供一个ActionSupport基类去实现 常用的接口。Action接口不是必须的,任何有execute标识的POJO对象都可以用作Struts2的Action对象。

线程模式: 
• Struts1 Action是单例模式并且必须是线程安全的,因为仅有Action的一个实例来处理所有的请求。单例策略限制了Struts1 Action能作的事,并且要在开发时特别小心。Action资源必须是线程安全的或同步的。 
• Struts2 Action对象为每一个请求产生一个实例,因此没有线程安全问题。(实际上,servlet容器给每个请求产生许多可丢弃的对象,并且不会导致性能和垃圾回收问题)

Servlet 依赖: 
• Struts1 Action 依赖于Servlet API ,因为当一个Action被调用时HttpServletRequest 和 HttpServletResponse 被传递给execute方法。 
• Struts 2 Action不依赖于容器,允许Action脱离容器单独被测试。如果需要,Struts2 Action仍然可以访问初始的request和response。但是,其他的元素减少或者消除了直接访问HttpServetRequest 和 HttpServletResponse的必要性。

可测性: 
• 测试Struts1 Action的一个主要问题是execute方法暴露了servlet API(这使得测试要依赖于容器)。一个第三方扩展--Struts TestCase--提供了一套Struts1的模拟对象(来进行测试)。 
• Struts 2 Action可以通过初始化、设置属性、调用方法来测试,“依赖注入”支持也使测试更容易。

捕获输入: 
• Struts1 使用ActionForm对象捕获输入。所有的ActionForm必须继承一个基类。因为其他JavaBean不能用作ActionForm,开发者经常创建多余的类捕获输入。动态Bean(DynaBeans)可以作为创建传统ActionForm的选择,但是,开发者可能是在重新描述(创建)已经存在的JavaBean(仍然会导致有冗余的javabean)。 
• Struts 2直接使用Action属性作为输入属性,消除了对第二个输入对象的需求。输入属性可能是有自己(子)属性的rich对象类型。Action属性能够通过web页面上的taglibs访问。Struts2也支持ActionForm模式。rich对象类型,包括业务对象,能够用作输入/输出对象。这种ModelDriven 特性简化了taglib对POJO输入对象的引用。

表达式语言: 
• Struts1 整合了JSTL,因此使用JSTL EL。这种EL有基本对象图遍历,但是对集合和索引属性的支持很弱。 
• Struts2可以使用JSTL,但是也支持一个更强大和灵活的表达式语言--"Object Graph Notation Language" (OGNL).

绑定值到页面(view): 
• Struts 1使用标准JSP机制把对象绑定到页面中来访问。 
• Struts 2 使用 "ValueStack"技术,使taglib能够访问值而不需要把你的页面(view)和对象绑定起来。ValueStack策略允许通过一系列名称相同但类型不同的属性重用页面(view)。 
  
类型转换: 
• Struts 1 ActionForm 属性通常都是String类型。Struts1使用Commons-Beanutils进行类型转换。每个类一个转换器,对每一个实例来说是不可配置的。 
• Struts2 使用OGNL进行类型转换。提供基本和常用对象的转换器。

校验:  
• Struts 1支持在ActionForm的validate方法中手动校验,或者通过Commons Validator的扩展来校验。同一个类可以有不同的校验内容,但不能校验子对象。 
• Struts2支持通过validate方法和XWork校验框架来进行校验。XWork校验框架使用为属性类类型定义的校验和内容校验,来支持chain校验子属性

Action执行的控制: 
• Struts1支持每一个模块有单独的Request Processors(生命周期),但是模块中的所有Action必须共享相同的生命周期。 
• Struts2支持通过拦截器堆栈(Interceptor Stacks)为每一个Action创建不同的生命周期。堆栈能够根据需要和不同的Action一起使用。

Struts2 优点收集整理

Struts2比Struts1已经有了很大的进步,优点很多,其中主要是: 
增强页面数据处理功能(OGNL、valueStack)。
简化捕获表单数据对象过程 (类型转换)
提供灵活丰富功能和插件, 易于使用和扩展 (拦截器、插件支持、Action生命周期、校检);
提高线程安全性(单例—原型);
提高可测性(不依赖servlet、struts,提供依赖注入);

表达式语言:

• Struts1 整合了JSTL,因此使用JSTL EL。这种EL有基本对象图遍历,但是对集合和索引属性的支持很弱。 
• Struts2可以使用JSTL,但是也支持一个更强大和灵活的表达式语言--"Object Graph Notation Language" (OGNL). 
【((EntCustomer)jack.getCustomer()).getTrustId()----jack.customer.trustId】 
** 不需关注对象类型,不需进行类型转换 
** 表达方式更简短和直观

绑定值到页面(view):

• Struts 1使用标准JSP机制把对象绑定到页面中来访问。 
• Struts 2 使用 "ValueStack"技术,使taglib能够访问值而不需要把你的页面(view)和对象绑定起来。ValueStack策略允许通过一系列名称相同但类型不同的属性重用页面(view)。

插件支持:

• Struts2是基于插件开发的框架,能简单快速的使用大量成熟实用的插件和视图

依赖注入:

• Struts2提供依赖注入,并能很好的和spring ioc整合。

Struts2 AOP-拦截器:

• Struts2提供强大的、可插拔的拦截器以及拦截器栈, 
个人觉得Struts1是基于servlet开发,Struts2是基于Filter开发,相对于现在的企业来说Struts1的技术成熟,便于维护,而且现在的许多程序员使用SSH框架时,还是多选用struts1来开发~~ 当然Struts2安全性比Struts1要高~~

Action生命周期控制:

• Struts1支持每一个模块有单独的Request Processors(生命周期),但是模块中的所有Action必须共享相同的生命周期。 
• Struts2支持通过拦截器堆栈(Interceptor Stacks)为每一个Action创建不同的生命周期。堆栈能够根据需要和不同的Action一起使用。

线程安全:

• Struts1 Action是单例模式并且必须是线程安全的,因为仅有Action的一个实例来处理所有的请求。单例策略限制了Struts1 Action能作的事,并且要在开发时特别小心。Action资源必须是线程安全的或同步的。 
• Struts2 Actions是原型模式,对象为每一个请求产生一个实例,因此没有线程安全问题。(实际上,servlet容器给每个请求产生许多可丢弃的对象,并且不会导致性能和垃圾回收问题)

Struts框架依赖:

• Struts1要求Action类继承一个抽象基类。Struts1的一个普遍问题是使用抽象类编程而不是接口。 
• Struts 2 Action类可以实现一个Action接口,也可实现其他接口,使可选和定制的服务成为可能。Struts2提供一个ActionSupport基类去实现常用的接口。Action接口不是必须的,任何有execute标识的POJO对象都可以用作Struts2的Action对象。

Servlet 依赖:

• Struts1 Action 依赖于Servlet API ,因为当一个Action被调用时HttpServletRequest 和 HttpServletResponse 被传递给execute方法。 
• Struts 2 Action不依赖于容器,允许Action脱离容器单独被测试。如果需要,Struts2 Action仍然可以访问初始的request和response。但是,其他的元素减少或者消除了直接访问HttpServetRequest 和 HttpServletResponse的必要性。

捕获输入[表单数据封装对象:]:

• Struts1 使用ActionForm对象捕获输入。所有的ActionForm必须继承一个基类。因为其他JavaBean不能用作ActionForm,开发者经常创建多余的类捕获输入。动态Bean(DynaBeans)可以作为创建传统ActionForm的选择,但是,开发者可能是在重新描述(创建)已经存在的JavaBean(仍然会导致有冗余的javabean)。 
• Struts 2直接使用Action属性作为输入属性,消除了对第二个输入对象的需求。输入属性可能是有自己(子)属性的rich对象类型。Action属性能够通过 web页面上的taglibs访问。Struts2也支持ActionForm模式。rich对象类型,包括业务对象,能够用作输入/输出对象。这种 ModelDriven 特性简化了taglib对POJO输入对象的引用。

可测性:

• 测试Struts1 Action的一个主要问题是execute方法暴露了servlet API(这使得测试要依赖于容器)。一个第三方扩展--Struts TestCase--提供了一套Struts1的模拟对象(来进行测试)。 
• Struts 2 Action可以通过初始化、设置属性、调用方法来测试,“依赖注入”支持也使测试更容易。

类型转换:

• Struts 1 ActionForm 属性通常都是String类型。Struts1使用Commons-Beanutils进行类型转换。每个类一个转换器,对每一个实例来说是不可配置的。 
• Struts2 使用OGNL进行类型转换。提供基本和常用对象的转换器。

校验:

• Struts 1支持在ActionForm的validate方法中手动校验,或者通过Commons Validator的扩展来校验。同一个类可以有不同的校验内容,但不能校验子对象。 
• Struts2支持通过validate方法和XWork校验框架来进行校验。XWork校验框架使用为属性类类型定义的校验和内容校验,来支持chain校验子属性

Struts2的新特性new

Struts 1.0非常成熟,因此得到众多开发社区的有力支持,而且说明文档内容完备。不过在过去的几年里,许多开源社区的Web框架纷纷登台亮相,所以它需要跟上 Web应用需求不断变化的形势,这就有必要构建下一代Struts框架。力求满足这个要求的初始提案是Struts Ti,这种简化的MVC Model 2框架可用于让需要更少配置、更好结构和控制器特性的人开发Web应用。

WebWork项目由Open Symphony社区启动,面向Struts开发社区。它旨在满足那些希望寻求类似Struts的一种框架,但有更好特性的人的需要。WebWork框架 于2002年发布。独立运作了几年后, WebWork和Struts两个社区在2005年12月联合起来,开发了新版本的Struts,即Struts 2。Struts 2实际上就是Struts 1与WebWork的结合体。Struts的这个新版本更易使用,更接近Struts框架的最初版本。

Struts 2.0的新特性
改进的设计: 与Struts 1相比,Struts 2的所有类都基于接口,核心接口独立于HTTP。这些API并不依赖服务器小程序API。

简化的Action: Struts 2 Action类独立于框架,是简化的普通Java对象(POJO)。拥有execute()方法的任何Java类都可以用做Action类。

POJO表单: Struts 2不支持ActionForms特性。ActionForms中定义的属性可以直接放在Action类上。不需要使用所有的String属性。

智能默认值: Struts 2配置文件中的大多数配置元素都会有默认值,所以不需要设定值,除非需要不同的值。这有助于减少在XML文件中需要进行的配置。Struts 2支持注释,这带来了更大的方便。

改进的结果: 在Struts 2中,

>forward<标签被<result>标签取代。不像 ActionForwards,Struts 2结果可以帮助准备响应,并提供构建多种输出类型的灵活性。

改进的标签: Struts 2标签不单单发送输出数据,还能提供样式表驱动标记,这样就可以用较少的代码构建一致性页面。Struts 2标签现在可与FreeMarker、Velocity及类似模板引擎配合使用。

引入拦截器: Struts 2为拦截器(interceptor)提供了全面支持。拦截器可在Action类执行前后加以执行。拦截器经配置后,可以把工作流程或者验证等常见功能作 用到请求上。所有请求通过一组拦截器传送,之后再发送到Action类。Action类被执行后,请求按照相反顺序再次通过拦截器传送。

支持Ajax: 为了创建使用Ajax的动态Web应用,Struts 2提供了Ajax主题,从而大大改进了交互应用。面向Ajax的Struts 2标签基于Dojo窗口组件。还有用于其他框架的插件。

快速启动: 部署配置文件可以重新装入; 因而,可以动态地进行许多变化,用不着重新启动Web容器。

状态复选框: Struts 2框架可自动跟踪复选框,如果缺少了某复选框,就会采用默认值false。因而,不像在Struts 1中,复选框不需要对false值进行特殊处理。

易于测试: Struts 2 Actions独立于HTTP,因而与框架中立。无须使用模拟对象(mock object),就很容易测试。

使用注释: 使用Struts 2开发的应用可以使用Java 5注释,作为XML和Java属性配置之外的一个替代办法。注释尽量减少了对XML的需要。Action、拦截器、验证及类型转换方面都有注释。

易于插入: 只要把插件JAR文件放到\WEB-INF\lib目录中,即可轻松安装Struts 2插件,不需要手动配置。

便于与Spring集成: Struts 2 Action能够感知Spring(Spring-aware)。只要为某个应用添加Spring beans,就可以添加对Spring的支持。

易于定制的控制器: Struts 1允许请求处理程序可按照模块来定制,在Struts 2中,需要的话,可以按照动作来定制请求处理。

Struts框架开发安全特性

此文是我前年研究struts框架相关安全特性做的总结,这里发上来,各位安全工作人员在查找Struts相关应用的漏洞有一定用处,但因为是去年的文档,因此可能有一些过时内容,大家在参考时需要注意。

前言 
Struts是目前J2ee Web开发中最常见使用的MVC框架。由于使用框架编写的应用程序与原生jsp编写的Web程序区别较大,因此有必要专门撰写一篇文档描述Struts框架的安全特性,及其检查方法。

Struts介绍 
Struts是一套MVC框架,目前分为两个大版本号。1.x系列,已经放弃开发,是一个较为简单的框架,安全特性也较少。2.x系列则是直接与webwork这个框架合并之后基于webwork重新开发的一套全新框架。目前主流使用框架基本就是2.x系列。

Struts1 
s1.png 
图 2.1 struts1架构图

如上图所示,struts 1.x系列的模型主要分为几个部分:最主要的Dispatcher、Controller是使用J2ee的servlet实现的,用户请求过来,通过用户自定义的一系列过滤器(filter)之后,servlet分析匹配其url结构,再转给各action类,最后进行form的填充控制、View层的调用展现。其主要代码是在action中实现的,可以根据struts-config.xml中的配置,根据url->action->view的对应关系一一查看其代码。Struts1中的统一控制一般做在filter中,或者由form的校验函数做数据有效性控制。

Struts2 
s2.png 
图 2.2 struts2架构图

而struts2.x的架构就复杂很多,也细致的多。用户的请求过来,先经过一系列过滤器(Filter实现),最后一个过滤器通过actionProxy才是真正对不同的action派发调用,其中的派发规则由struts.xml定义。这几部分相加,才类似于之前Struts1中的ActionServlet的作用。在调用action之前,还有类似Hook的机制,在action执行前后、view执行前后分别有可以统一执行的用户自定义代码。在struts2的说法中,叫做拦截器(Interceptor)。通常struts2中的统一控制就在过滤器、拦截器、校验器这几个方面做控制,其中后两者最普遍。

如何区分Struts框架应用程序 
URL中以.do结尾的,struts1框架;以.action结尾的,struts2框架。 
Struts1由于是通过servlet进行的action控制,因此主要配置文件在WEB-INF/web.xml及struts-config.xml这两个文件中;Struts2的配置文件则主要就是WEB-INF/struts.xml。 
目录组织结构中如果有Filter、Interceptor的定义实现,通常是Struts2的代码。 
如果有专门的xxxForm.java代码,一般是Struts1的项目;Struts2通常只有一些简单的Java Bean定义作为模型。

Struts框架安全特性

Struts1的白盒安全测试方法 
之前我们说过,Struts1中的统一控制一般做在filter中,或者由form的校验函数做数据有效性控制。因此,无论是哪一方面的统一控制,例如参数的统一过滤、验证是否登录、文件上传验证之类,通常是在Filter中进行的;而参数的有效性,例如email只允许[0-9a-zA-Z_@]。 
建议在读代码时,先通读web.xml和struts-config.xml两个文件,从web.xml中了解filter的设置,将所有filter通读一遍,了解总体上做了什么限制,再从struts-config.xml了解action与actionForm、View的对应关系,然后根据这些关系,检查form中的参数有效性验证方法(validate函数)是否做了足够的检查,以及view中是否有基本的html过滤。具体测试case这里不多言,只要找对地方,java的测试case和其他语言也基本都差不多。

Struts1安全特性

参数获取 
通常使用J2ee中最常见的Request.getParamter()方法获取用户输入。此方法结合了GET/POST中提交的变量,如果两者有重名,则GET获取的优先,获取的内容非常原始,没有任何改变。不同于PHP中的$_REQUEST变量,Request.getParamter方法并没有包含cookie中获取的变量。 
actionForm中获取的变量也是框架通过上述方法获取的,因此虽然看起来是直接使用没有通过函数获取,实际上也是一样。

文件操作 
文件下载在struts中并没有做任何限制。在文件上传中,一般是使用Apache-Common-FileUpload的组件。其中也未替代用户做任何限制和检查,需要手工实现扩展名判断、验证等代码。因此如果action中的逻辑代码没有做任何检查,基本可以判断存在问题。

前端防范 
一般Struts1使用jsp作为默认的前端引擎,常见的过滤方式与jsp相同,不做赘述。

CSRF防范 
Struts1提供了一个生成并验证Token的api(isTokenVaild),在检查是否防范了CSRF的时候,可以查看应用程序是否使用了这个API(也可以查看提交的请求包中是否包含org.apache.struts.taglib.html.TOKEN这个变量)。如果未使用,就可以检查是否在Filter之类的地方做了统一的自己实现的CSRF token验证防范。 
Struts1提供的Token值是存储在SESSION中的,因此这里就存在一个bug。由于Token在session中保存的变量名不变,因此如果一个用户打开了多个窗口,只有最后一个窗口设置的token值有效。这里需要多加注意。

其他 
此外,Struts1有个特性:一个Action类在程序周期中只有一个实例,常驻内存。因此,在这个类中的属性和变量是共享的,不同用户访问的不同请求都是如此。因此如果程序中的逻辑依靠Action内部变量传送敏感信息,则其他用户也可能改写、读取。

Struts2的白盒安全测试方法

Struts2的安全测试主要方法论与S1一致,也多是通过查看struts.xml和web.xml中的配置,了解url->action->view的关系,以及不同url中涉及到的过滤器、拦截器、验证器(一般在validation.xml和className-validation.xml中配置)的关系。了解了这些,在头脑中有一个清晰的数据流脉络,然后再检查这些控制措施是否做到位,是否有疏漏即可。一般来说,S2的控制大都在拦截器和验证器中进行,常见的有是否登录、文件上传格式检查、参数有效性检查等。S2默认提供了很多拦截器,做了以上功能,这些在下面的安全特性中会提及。

Struts2的安全特性

参数获取 
与S1不同,S2中的参数获取虽然也可以通过Request.getParamter()方法,但是很少使用。因为action类中定义过getter/setter方法的变量,如果用户在请求中提交了同名的变量,框架会自动将其值注入到action实例中的对应变量中去,并且会做响应的类型转换。这一切是通过defaultStack中默认的Param拦截器实现的,利用拦截器,在action执行前,将用户传入的数值使用Request.getParamter()获取后并经过解析自动注入。 
这一点请一定注意。因为如果action中的内部成员变量之前有一个默认值,一旦用户提交了同名变量,就可以覆盖此值。这样就会直接导致后续依赖此默认值的逻辑发生重大变化。

文件操作 
下载文件没有限制,需要自行编写代码控制。 
上传文件,S2默认有一个FileUploadInterceptor的拦截器,提供了三种限制方法,都在struts.xml中配置:

allowedTypes(允许文件的mime-type值,可伪造) 
maxmumSize(允许文件最大的字节数) 
allowedExtensions(允许文件的扩展名)

由于早期S2框架文档的误导,提供的例子程序中只限制了allowedTypes,因此导致多数s2应用程序存在修改http包修改mime-type导致任意上传漏洞。因此在做安全测试的时候,一定要检查是否设置了allowedExtensions作为白名单,而不单单是allowedTypes。另外即使做了扩展名限制,请注意这个可能还存在多扩展名文件的问题。 
如果上传没有使用默认的FileUploadInterceptor,请检查程序逻辑中是否对文件上传做了严格的限定。

CSRF防范 
S2中也提供了防范重复提交的Token机制。与S1不同的是此次他是使用TokenInterceptor这个拦截器的方式,在action执行前统一进行验证。Token值也是保存在session中,因此同样存在S1框架中Token的bug。 
此外,这个Token机制还有个可以被绕过的0day漏洞:由于TokenInterceptor在验证用户提交上来的请求时,先从用户请求中的struts.token.name值作为session中的key,然后比对用户请求中提交的token值是否与session中key对应的值相匹配,如匹配则通过。但是,如果攻击者预先知晓session中已保存的一个值,例如username=admin,则攻击者可以直接将csrf包中的struts.token.name设置为username,然后token值设置为admin,即可轻易绕过csrf token防范。 
因此,如果经检查的应用中使用了默认的token拦截器,请提醒开发人员弥补以上不足。如自行实现防重复提交的代码,请仔细检查其逻辑的严密性。

动态方法调用 
Struts2中存在一个特性,叫做动态方法调用。当你请求actionName!methodName.action这样的URL时,框架不会调用action中的默认入口execute(),而是会寻找action中名叫methodName的方法,并直接调用。通过这种方式,可能暴露action类中未经过验证的内部接口,也可能绕过一些权限验证。 
因此,在测试过程中,如果程序本身没有使用到这个特性,请建议RD在struts.xml中设置一个constant将struts.enable.DynamicMethodInvocation属性设置为false,禁止此特性。

前端模板 
S2自带的taglib中的变量输入都经过了自动html转义。一般无问题。但是请注意参数名前带感叹号,则表示没有转义。安全检测时请务必注意。 
如果使用其他模板引擎,请根据其他引擎的过滤规则进行检查。

其他 
与s1不同,s2中每一个请求对应一个不同的action实例,没有action实例中变量共享的问题。 
S2的action中execute方法,根据方法返回的值来决定最后调用哪一个view模板。因此,结合动态方法调用和自动变量注入的特性,如请求actionName!getUsername.action?username=pass。而action中对应“pass”这个返回结果的view又是个包含敏感信息的模板,就可能产生问题。因此在安全测试的过程中需要特别注意。

Java Struts 特性和新特性总结相关推荐

  1. Java 11 正式发布,新特性解读

    Java 11 正式发布,新特性解读 杨晓峰   2018 年 9 月 26 日 话题:Java语言 & 开发 不知不觉 JDK 11 已经发布了,从 9 开始,JDK 进入了让人学不动的更新 ...

  2. java的发展(8-17新特性整理)

    java java的诞生与历史: 简介:Java是一门面向对象的编程语言,不仅吸收了C++语言的各种优点,还摒弃了C++里难以理解的多继承.指针等概念,因此Java语言具有功能强大和简单易用两个特征. ...

  3. Java基础之Java8 新特性

    hp实训8.19_Java基础之Java8新特性 // 信息展示方法 ,接口中,就可以提供一种实现. 就可以使用这种功能.default void print() {System.out.printl ...

  4. 不停歇的Java即将发布JDK16新特性速览及从菜鸟到架构师[图]

    一.不停歇的Java即将发布JDK16新特性速览 当开发者深陷Java8版本之际,这边下一版本Java16有了最新的消息,与Java15一样,作为短期版本,Oracle仅提供6个月的支持. 根据发布计 ...

  5. 【JAVA拾遗】Java8新特性合辑

    [JAVA拾遗]Java8新特性合辑 文章目录 [JAVA拾遗]Java8新特性合辑 0. 逼逼 [--/--]126 Lambda Expressions & Virtual Extensi ...

  6. 详解 Java 17中的新特性:“密封类”

    作者:程序猿DD 博客:https://blog.didispace.com/ Java 17推出的新特性Sealed Classes经历了2个Preview版本(JDK 15中的JEP 360.JD ...

  7. Java 17 版本的新特性

    Java 17 版本的新特性

  8. 详解Java 8十大新特性

    前言: Java 8 已经发布很久了,很多报道表明Java 8 是一次重大的版本升级.在Java Code Geeks上已经有很多介绍Java 8新特性的文章,例如Playing with Java ...

  9. ES10新特性01-ES10新特性

    ES10新特性01-ES10新特性 文章目录 ES10新特性01-ES10新特性 一.Object.fromEntries 二.字符串的扩展方法-trimStart 与 trimEnd 三.数组方法扩 ...

  10. html5 svg特性,HTML5新特性——HTML 5 Canvas vs. SVG

    Canvas 和 SVG 都允许您在浏览器中创建图形,但是它们在根本上是不同的. SVG SVG 是一种使用 XML 描述 2D 图形的语言. SVG 基于 XML,这意味着 SVG DOM 中的每个 ...

最新文章

  1. 中科院微生物所郭惠珊团队创建抗土传真菌黄萎病的陆地棉种质
  2. python下的橡皮线_python下载吴恩达deep learning编程习题
  3. 用Tcl定制Vivado设计实现流程
  4. vb.net2019-Accord.Net机器学习库安装与SVM简单分类
  5. 使用RMAN连接到数据库
  6. Http Server API路由请求到web程序
  7. LeetCode MySQL 1581. 进店却未进行过交易的顾客
  8. mysql注解实体类_jpa实体类生成mysql表及字段注解
  9. janusgraph整合mysql_图解图库JanusGraph系列-一文知晓“图数据“底层存储结构
  10. 一个 wince 开发经验的杰出blog
  11. 炸了!JetBrains 宣布:IntelliJ IDEA 彻底弃用 Log4j。。
  12. 基于Linux操作系统的在线英英词典C语言代码
  13. android 蓝牙串口指令,蓝牙串口助手
  14. 苹果7pnfc功能门禁卡_苹果手机怎么刷门禁卡?iPhone刷门禁卡的设置方法
  15. python批量裁剪图片_python实现图片批量剪切示例
  16. 2.4g无线模块 java_ESP32 2.4G无线模块 WIFI和蓝牙双模模块
  17. 买的也忒波折了。。。
  18. LeetCode207: 课程表(字节手撕算法拓扑排序)
  19. [转载]学习整理英文单词收藏
  20. 半导体巨头如何拼了老命为摩尔定律延寿

热门文章

  1. jQuery 选择器 之 案例:淘宝服饰精品案例
  2. 用python pandas三行代码实现excel转csv
  3. linux下oracle数据库由于参数文件丢失导致的数据库服务启动失败,报“failure in processing system parameters“错误问题解决
  4. C# 学习笔记(18)操作SQL Server 中
  5. freeRtos学习笔记 (8) 任务通知
  6. C程序中变量存放方式介绍
  7. [YTU]_1985( C语言实验——保留字母)
  8. 解决方法WindowsError: [Error 193] %1 is not a valid Win32 application
  9. java html字符串,java字符串方法
  10. 绘图的尺寸_AutoCAD新功能:参数化绘图,绘制看似简单,实际复杂,案例详解...