Spring Framework 官方文档学习(四)之Validation、Data Binding、Type Conversion
本篇太乱,请移步:
Spring Framework 官方文档学习(四)之Validation、Data Binding、Type Conversion(一)
写了删删了写,反复几次,对自己的描述很不满意,表达能力还是不行啊。另外,格式太花了,很不喜欢。
前提
1、什么是JavaBean?
简单类,无参构造,有SETTER/GETTER,其对应的字段称为属性。--其实还有isXxx,用于布尔类型的属性,略。
详见 https://en.wikipedia.org/wiki/JavaBeans
注意,这里的JavaBean不是Spring的bean。
好了,现在已经有了属性(property)的概念,下面所有的东西都是围绕它来进行的。
2、需求
我们应该明白一点,所有的技术都是源自需求而出现的(不严谨)。搞明白需求就搞明白了它们的应用场景。
假定我们有一个桌面应用(下文用 app 代替 桌面应用),需要你输入生日,然后该app会输出你的年龄。看起来很简单吧,app的后台逻辑只要用当前日期减去你的生日即可,但是,现实不是这样子的。
问题一,我们输入的永远是字符串,字符串需要转成日期格式才能被我们的app用使用。--对应 类型转换
问题二,我们输入的字符串转成的日期怎么给app后台逻辑使用? --对应 数据绑定
问题三,人的年龄是有限制的,不能为负数,不能太大(例如超过了200)。 --对应 校验
看到这里,你应该已经搞明白Validation、Data Binding、Type Conversion三者之间的关系了。
同样的问题也出现在浏览器与服务器的交互之中,因为请求与响应,大都是被解析成字符串。
简介
1、什么是Validation?
Validation 就是对属性的值进行校验。--【谁的属性?JavaBean的!】
例如,User的属性age,我的预期是[0, 100],其他所有值都是非法的,那就校验一下好了。
Spring提供了Validator 接口,能在应用的任意layer使用,来完成Validation的工作。
2、什么是数据绑定?
数据绑定就是将数据绑定到属性上!--【谁的属性?JavaBean的!】
两种方法,通过对象调用SETTER,或者,通过反射调用对象的SETTER,二者都是给属性设值。--谁的对象?JavaBean的!
例如,user.setAge(20)。或者通过反射 -- 在各种框架中常用。
Spring提供了DataBinder 来做具体的Data binding工作。
注意:Validator 和DataBinder 构成了validation 包。
3、什么是类型转换?
将一个类型的对象转成另一个类型的对象,例如String和Date互转等。 --【谁的类型?属性的!】
Spring提供了PropertyEditor 以及core.convert 包和format 包。后两者是Spring 3 引入的,可以看作PropertyEditor 的替代品,更简单。
注意:PropertyEditor 概念是 JavaBeans specification 的一部分。
BeanWrapper ,这是一个接口,Spring还提供了一个实现BeanWrapperImpl 。但是,这个东西是很底层的概念,用户一般不必直接使用它,了解即可。DataBinder 和底层 BeanWrapper 都是使用 PropertyEditors 来解析和格式化属性值。PropertyEditor的替代品,更简单。稍后谈。 正文
1、使用Validator接口进行Validation
Validator 接口进行校验,该接口只有两个方法,support(..)用于判断是否支持某类型,validate(..)则进行校验。Validator 接口形参是一个Errors 对象,当校验时,可以将失败结果报告给该对象。public class Person {
private String name;
private int age;
// the usual getters and setters...略
}
public class PersonValidator implements Validator {
public boolean supports(Class clazz) {
return Person.class.equals(clazz); // 仅支持Person类
}
public void validate(Object obj, Errors e) {
ValidationUtils.rejectIfEmpty(e, "name", "name.empty");
Person p = (Person) obj;
if (p.getAge() < 0) { // 年龄不能小于0
e.rejectValue("age", "negativevalue");
} else if (p.getAge() > 110) { // 年龄不能大于110
e.rejectValue("age", "too.darn.old");
}
}
}
上面的代码一目了然,实现Validator 接口,完成两个方法即可。
如果是复合类(包含其他类字段),还可以注入相应的Validator -- 复用,高效。
2、错误码与错误消息(暂略)
MessageCodesResolver DefaultMessageCodesResolver 3、Bean操作 和 BeanWrapper
BeanWrapper 接口和其实现 BeanWrapperImpl 。BeanWrapper 就是封装一个bean,对其进行操作,例如set/get property。支持嵌套属性等特点,详见 table 9.1 。BeanWrapper 支持添加标准JavaBean PropertyChangeListeners and VetoableChangeListeners的能力,无须在目标类中编码。(监听器)DataBinder and the BeanFactory 中。3.1、set/get属性
BeanWrapper company = new BeanWrapperImpl(new Company()); // setting the company name..
company.setPropertyValue("name", "Some Company Inc."); // ... can also be done like this:
PropertyValue value = new PropertyValue("name", "Some Company Inc.");
company.setPropertyValue(value); // ok, let's create the director and tie it to the company:
BeanWrapper jim = new BeanWrapperImpl(new Employee());
jim.setPropertyValue("name", "Jim Stravinsky");
company.setPropertyValue("managingDirector", jim.getWrappedInstance()); // retrieving the salary of the managingDirector through the company
Float salary = (Float) company.getPropertyValue("managingDirector.salary");
3.2、内建的PropertyEditor实现
Object and a String之间的转换。-- 注意,是对象和字符串之间的转换,不是任意类型间的转换。Date 可以用人类可读的方式来描述。这可以通过注册自定义的java.beans.PropertyEditor类型的editor来实现(--卧槽,刚意识到这不是Spring的东西),嗯,注册在BeanWrapper 上或者IoC容器中。详见Javadoc。PropertyEditor 的例子:ClassEditor 来转换成相应的类。PropertyEditors 来完成的。 PropertyEditors ,它们都在org.springframework.beans.propertyeditors 包中。它们的多数,默认已经被BeanWrapperImpl注册了。当然,你也可以注册自己的变体来覆盖默认的:Table 9.2. Built-in PropertyEditors
| Class | Explanation |
|---|---|
|
|
Editor for byte arrays. Strings will simply be converted to their corresponding byte representations. Registered by default by |
|
|
Parses Strings representing classes to actual classes and the other way around. When a class is not found, an |
|
|
Customizable property editor for |
|
|
Property editor for Collections, converting any source |
|
|
Customizable property editor for java.util.Date, supporting a custom DateFormat. NOT registered by default. Must be user registered as needed with appropriate format.默认没注册! |
|
|
Customizable property editor for any Number subclass like |
|
|
Capable of resolving Strings to |
|
|
One-way property editor, capable of taking a text string and producing (via an intermediate |
|
|
Capable of resolving Strings to |
|
|
Capable of resolving Strings to |
|
|
Capable of converting Strings (formatted using the format as defined in the javadocs of the |
|
|
Property editor that trims Strings. Optionally allows transforming an empty string into a |
|
|
Capable of resolving a String representation of a URL to an actual |
Font、Color以及大多数基本类型的PropertyEditor 的实现。PropertyEditor 类(不需要显式的注册它们)--如果它们和它们处理的类在相同包下,且其名字以被其处理类的名字加上“Editor”的话。com
chank
pop
Foo
FooEditor // the PropertyEditor for the Foo class
注意,② 还可以使用标准BeanInfo JavaBean机制。下例就使用了该机制来显式注册相关类属性的一个或多个PropertyEditor 实例。(使用已有的editor)
com
chank
pop
Foo
FooBeanInfo // the BeanInfo for the Foo class
public class FooBeanInfo extends SimpleBeanInfo {
public PropertyDescriptor[] getPropertyDescriptors() {
try {
final PropertyEditor numberPE = new CustomNumberEditor(Integer.class, true);
PropertyDescriptor ageDescriptor = new PropertyDescriptor("age", Foo.class) {
public PropertyEditor createPropertyEditor(Object bean) {
return numberPE;
};
};
return new PropertyDescriptor[] { ageDescriptor };
}
catch (IntrospectionException ex) {
throw new Error(ex.toString());
}
}
}
3.2.1、注册额外定制的PropertyEditor
BeanFactory 实现中使用,但更建议在ApplicationContext中使用。BeanWrapper 来处理property conversions。(前面有提到,BeanWrapperImpl 会自动注册一些内建的editors)。此外,具体的ApplicationContexts 还会覆盖或者添加额外的editors。(这句很重要) package example;
public class ExoticType {
private String name;
public ExoticType(String name) {
this.name = name;
}
}
public class DependsOnExoticType {
private ExoticType type;
public void setType(ExoticType type) {
this.type = type;
}
}
下面就会调用幕后的PropertyEditor --注意,这里的value是String,后台editor会将其转成 ExoticType类型。
<bean id="sample" class="example.DependsOnExoticType">
<property name="type" value="aNameForExoticType"/>
</bean>
该editor实现大概类似这样:
// 将String转成ExoticType对象
package example; public class ExoticTypeEditor extends PropertyEditorSupport { public void setAsText(String text) {
setValue(new ExoticType(text.toUpperCase()));
}
}
然后,就到了最后一步,也是这里的主题,使用CustomEditorConfigurer 将新的PropertyEditor 注册到ApplicationContext。
如下:
<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
<property name="customEditors">
<map>
<entry key="example.ExoticType" value="example.ExoticTypeEditor"/>
</map>
</property>
</bean>
③ 使用PropertyEditorRegistrars,需要手动创建它。在复用时很有用,因为它打包了一组editor,拿来即用。(听起来,是类似map或者set之类的集合??)
提醒,下面这段话可能比较绕,建议略过,直接看代码,简洁明了。
PropertyEditorRegistrars 配合接口 PropertyEditorRegistry 使用。这个接口被BeanWrapper(还有DataBinder)实现了。PropertyEditorRegistrars 配合CustomEditorConfigurer 使用时特别方便,后者有一个方法setPropertyEditorRegistrars(..),以这种方式添加到CustomEditorConfigurer 中的PropertyEditorRegistrars 可以轻松的共享给DataBinder 和Spring MVC Controllers。 Furthermore, it avoids the need for synchronization on custom editors:每个bean创建时,PropertyEditorRegistrar 都会创建新的PropertyEditor 实例。PropertyEditorRegistrar 实现: package com.foo.editors.spring;
public final class CustomPropertyEditorRegistrar implements PropertyEditorRegistrar {
public void registerCustomEditors(PropertyEditorRegistry registry) {
// 需要PropertyEditor实例
registry.registerCustomEditor(ExoticType.class, new ExoticTypeEditor());
// 可以注册任意多的PropertyEditor...
}
}
插一句,org.springframework.beans.support.ResourceEditorRegistrar 也是一个实现,可以参考下。
CustomEditorConfigurer ,注入我们的CustomPropertyEditorRegistrar :<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
<property name="propertyEditorRegistrars">
<list>
<ref bean="customPropertyEditorRegistrar"/>
</list>
</property>
</bean> <bean id="customPropertyEditorRegistrar" class="com.foo.editors.spring.CustomPropertyEditorRegistrar"/>
最后,在使用Spring MVC框架时,使用PropertyEditorRegistrars 配合data-binding Controllers(如SimpleFormController)会是非常方便的(--暂时不明白,以后再来看吧)。见下例:
public final class RegisterUserController extends SimpleFormController {
private final PropertyEditorRegistrar customPropertyEditorRegistrar;
public RegisterUserController(PropertyEditorRegistrar propertyEditorRegistrar) {
this.customPropertyEditorRegistrar = propertyEditorRegistrar;
}
protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder) throws Exception {
this.customPropertyEditorRegistrar.registerCustomEditors(binder);
}
// other methods to do with registering a User
}
这种风格的PropertyEditor 注册能简洁代码(the implementation of initBinder(..) is just one line long!),且允许通用的PropertyEditor 注册代码包含在一个类中--然后由所有需要的Controllers 共享。
4、Spring 类型转换
4.1、Converter SPI
package org.springframework.core.convert.converter;
public interface Converter<S, T> {
T convert(S source);
}
想要创建自己的converter,实现这个接口即可。
DefaultConversionService 默认已注册了)。StringToInteger : package org.springframework.core.convert.support;
final class StringToInteger implements Converter<String, Integer> {
public Integer convert(String source) {
return Integer.valueOf(source);
}
}
4.2、ConverterFactory
package org.springframework.core.convert.converter;
public interface ConverterFactory<S, R> {
<T extends R> Converter<S, T> getConverter(Class<T> targetType);
}
例子:
package org.springframework.core.convert.support;
final class StringToEnumConverterFactory implements ConverterFactory<String, Enum> {
public <T extends Enum> Converter<String, T> getConverter(Class<T> targetType) {
return new StringToEnumConverter(targetType);
}
private final class StringToEnumConverter<T extends Enum> implements Converter<String, T> {
private Class<T> enumType;
public StringToEnumConverter(Class<T> enumType) {
this.enumType = enumType;
}
public T convert(String source) {
return (T) Enum.valueOf(this.enumType, source.trim());
}
}
}
4.3、GenericConverter(略)
4.4、ConditionalGenericConverter(略)
4.5、ConversionService API 转换服务API
package org.springframework.core.convert;
public interface ConversionService {
// 判断,能否将源类型转成目标类型
boolean canConvert(Class<?> sourceType, Class<?> targetType);
// 转换
<T> T convert(Object source, Class<T> targetType);
// 判断
boolean canConvert(TypeDescriptor sourceType, TypeDescriptor targetType);
// 转换
Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType);
}
从上面的代码可以推理,该接口的实现必定是先判断能否转换,如能转换再调用相应的converter进行转换。--问题,从哪调用converter?ConverterRegistry!
所以多数 ConversionService的实现 也实现了 ConverterRegistry,它提供了一个 SPI 以注册 converters 。在内部,一个ConversionService的实现委托注册的converters来执行类型转换逻辑。
GenericConversionService 是一个通用的实现,适用于多数环境。ConversionServiceFactory 提供了一个便捷的工厂以创建常见的ConversionService配置。4.6、Configuring a ConversionService 配置
<bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean"/>
注意,ConversionServiceFactoryBean的Javadoc说返回的conversionService是DefaultConversionService 实例。
默认的ConversionService可以在strings、numbers、enums、collections、maps以及其他常用类型之间进行转换。
converters 属性。其值可以是Converter、ConverterFactory或者GenericConverter的实现。<bean id="conversionService"
class="org.springframework.context.support.ConversionServiceFactoryBean">
<property name="converters">
<set>
<bean class="example.MyCustomConverter"/>
</set>
</property>
</bean>
个人心得:
①、非web项目的Spring应用,不会自动注册ConversionService bean。(web项目暂时没测)
②、@Configuration class 中进行ConversionService bean定义时,有几个选择:使用其实现,如GenericConversionService、DefaultConversionService 或者其他;使用ConversionServiceFactoryBean。区别在于,GenericConversionService 没有注册converters,DefaultConversionService 注册了很多converters,ConversionServiceFactoryBean 则提供了DefaultConversionService。-- 所以,一般情况下,直接使用ConversionServiceFactoryBean 即可。如下:
/**
* This implementation creates a DefaultConversionService.
* Subclasses may override createConversionService() in order to return a GenericConversionService instance of their choosing.
*
* 这个可以取代上面的DefaultConversionService,基本一致。
*
* @return
*/
@Bean
public ConversionServiceFactoryBean conversionService(){
return new ConversionServiceFactoryBean();
}
另,
FormattingConversionServiceFactoryBean.4.7、编码使用ConversionService
@Service
public class MyService { @Autowired
public MyService(ConversionService conversionService) {
this.conversionService = conversionService;
} public void doIt() {
this.conversionService.convert(...)
}
}
TypeDescriptor 提供了多种选项,使其变得简单直接:DefaultConversionService cs = new DefaultConversionService(); List<Integer> input = ....
cs.convert(input,
TypeDescriptor.forObject(input), // List<Integer> type descriptor
TypeDescriptor.collection(List.class, TypeDescriptor.valueOf(String.class)));
DefaultConversionService 自动注册的converters,可以适用于大多数环境。其中包含了collection converters、scalar converters,以及基本的Object到String的converter。同样的converters也可以使用DefaultConversionService 的static addDefaultConverters 注册到任意ConverterRegistry 中。5、Spring Field Formatting (Spring字段格式化)
core.convert 是一个通用目的的类型转换系统。提供了统一的ConversionService API和强类型的Converter SPI,以实现转换逻辑。Spring容器使用该系统来绑定bean property values。Short to a Long来完成expression.setValue(Object bean, Object value)尝试时,core.convert系统负责执行该强制。5.1、Formatter SPI
package org.springframework.format;
public interface Formatter<T> extends Printer<T>, Parser<T> {
}
public interface Printer<T> {
String print(T fieldValue, Locale locale);
}
import java.text.ParseException;
public interface Parser<T> {
T parse(String clientValue, Locale locale) throws ParseException;
}
format 包的子包中提供了几个Formatter的实现。number,datetime,datetime.joda。DateFormatter 。 package org.springframework.format.datetime;
public final class DateFormatter implements Formatter<Date> {
private String pattern;
public DateFormatter(String pattern) {
this.pattern = pattern;
}
public String print(Date date, Locale locale) {
if (date == null) {
return "";
}
return getDateFormat(locale).format(date);
}
public Date parse(String formatted, Locale locale) throws ParseException {
if (formatted.length() == 0) {
return null;
}
return getDateFormat(locale).parse(formatted);
}
protected DateFormat getDateFormat(Locale locale) {
DateFormat dateFormat = new SimpleDateFormat(this.pattern, locale);
dateFormat.setLenient(false);
return dateFormat;
}
}
5.2、注解驱动的Formatting
5.2.1、Format Annotation API
public class MyModel {
@DateTimeFormat(iso=ISO.DATE)
private Date date;
}
5.3、FormatterRegistry SPI
FormattingConversionService 适用于多数环境。5.4、FormatterRegistrar SPI
6、配置全局 date & time 格式
DateFormatterRegistrar -- 这取决于你是否使用Joda Time 库。@Configuration
public class AppConfig { @Bean
public FormattingConversionService conversionService() { // Use the DefaultFormattingConversionService but do not register defaults
DefaultFormattingConversionService conversionService = new DefaultFormattingConversionService(false); // Ensure @NumberFormat is still supported
conversionService.addFormatterForFieldAnnotation(new NumberFormatAnnotationFormatterFactory()); // Register date conversion with a specific global format
DateFormatterRegistrar registrar = new DateFormatterRegistrar();
registrar.setFormatter(new DateFormatter("yyyyMMdd"));
registrar.registerFormatters(conversionService); return conversionService;
}
}
WebMvcConfigurationSupport 并重写mvcConversionService()。对于XML来说,应该使用<mvc:annotation-driven>元素的'conversion-service'属性。See Section 22.16.3, “Conversion and Formatting” for details.7、Spring Validation
7.1、JSR-303 Bean Validation API概览
public class PersonForm {
@NotNull
@Size(max=64)
private String name;
@Min(0)
private int age;
}
7.2、配置一个Bean Validation Provider
javax.validation.ValidatorFactory or javax.validation.Validator。LocalValidatorFactoryBean 来配置默认的Validator:<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean"/>
上面,会引动Bean Validation使用其自身的启动机制来初始化。如果在classpath中有JSR-303/JSR-349 provider,如Hibernate Validator,会被自动探测到。
7.2.1、注入一个Validator
LocalValidatorFactoryBean implements both javax.validation.ValidatorFactory and javax.validation.Validator, as well as Spring’sorg.springframework.validation.Validator. javax.validation.Validator :import javax.validation.Validator; @Service
public class MyService { @Autowired
private Validator validator; }
②如果倾向于使用Spring Validation API,可以注入org.springframework.validation.Validator:
import org.springframework.validation.Validator; @Service
public class MyService { @Autowired
private Validator validator; }
7.2.2、配置自定义限制(Constraints)
LocalValidatorFactoryBean 配置了一个SpringConstraintValidatorFactory ,其使用Spring来创建ConstraintValidator实例。@Constraint 声明,紧接着相关联的ConstraintValidator 实现--使用Spring来依赖注入: @Target({ElementType.METHOD, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy=MyConstraintValidator.class)
public @interface MyConstraint {
}
import javax.validation.ConstraintValidator;
public class MyConstraintValidator implements ConstraintValidator {
@Autowired;
private Foo aDependency;
...
}
7.2.3、Spring-driven Method Validation
MethodValidationPostProcessor bean定义,它可以被集成到Spring context中。<bean class="org.springframework.validation.beanvalidation.MethodValidationPostProcessor"/>
为了支持Spring-driven method validation,所有的目标类都需要使用Spring的@Validated注解,可以选择声明校验组。详见MethodValidationPostProcessor的javadoc。
7.2.4、更多配置选项(略)
7.3、配置一个DataBinder
Foo target = new Foo();
DataBinder binder = new DataBinder(target);
binder.setValidator(new FooValidator()); // bind to the target object
binder.bind(propertyValues); // validate the target object
binder.validate(); // get BindingResult that includes any validation errors
BindingResult results = binder.getBindingResult();
Spring Framework 官方文档学习(四)之Validation、Data Binding、Type Conversion的更多相关文章
- Spring Framework 官方文档学习(四)之Validation、Data Binding、Type Conversion(一)
题外话:本篇是对之前那篇的重排版.并拆分成两篇,免得没了看的兴趣. 前言 在Spring Framework官方文档中,这三者是放到一起讲的,但没有解释为什么放到一起.大概是默认了读者都是有相关经验的 ...
- Spring Framework 官方文档学习(四)之Validation、Data Binding、Type Conversion(二)
接前一篇 Spring Framework 官方文档学习(四)之Validation.Data Binding.Type Conversion(一) 本篇主要内容:Spring Type Conver ...
- Spring Framework 官方文档学习(二)之IoC容器与bean lifecycle
到目前为止,已经看了一百页.再次感慨下,如果想使用Spring,那可以看视频或者找例子,但如果想深入理解Spring,最好还是看官方文档. 原计划是把一些基本接口的功能.层次以及彼此的关系罗列一下.同 ...
- Spring Framework 官方文档学习(一)介绍
http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#overview-maven-bom ...
- Spring Framework 官方文档学习(三)之Resource
起因 标准JDK中使用 java.net.URL 来处理资源,但有很多不足,例如不能限定classpath,不能限定 ServletContext 路径. 所以,Spring提供了 Resource ...
- Spring 4 官方文档学习(十二)View技术
关键词:view technology.template.template engine.markup.内容较多,按需查用即可. 介绍 Thymeleaf Groovy Markup Template ...
- Spring 4 官方文档学习(十一)Web MVC 框架
介绍Spring Web MVC 框架 Spring Web MVC的特性 其他MVC实现的可插拔性 DispatcherServlet 在WebApplicationContext中的特殊的bean ...
- Spring Boot 官方文档学习(一)入门及使用
个人说明:本文内容都是从为知笔记上复制过来的,样式难免走样,以后再修改吧.另外,本文可以看作官方文档的选择性的翻译(大部分),以及个人使用经验及问题. 其他说明:如果对Spring Boot没有概念, ...
- Spring boot官方文档学习(一)
个人说明:本文内容都是从为知笔记上复制过来的,样式难免走样,以后再修改吧.另外,本文可以看作官方文档的选择性的翻译(大部分),以及个人使用经验及问题. 其他说明:如果对Spring Boot没有概念, ...
随机推荐
- HDU4626+博弈
博弈... /* 博弈 对于当前人来说,如果完成自己的操作后,若mat[n][m]==0,则自己是胜者. 因为 如果mat其他位置不存在1了,肯定自己胜:如果存在1,则让下一位去反转那个1. */ # ...
- 深层神经网络框架的python实现
概述 本文demo非常适合入门AI与深度学习的同学,从最基础的知识讲起,只要有一点点的高等数学.统计学.矩阵的相关知识,相信大家完全可以看明白.程序的编写不借助任何第三方的深度学习库,从最底层写起. ...
- Mybatis-Generator自动生成代码
在使用mybatis开发的过程中,通常我们会给数据库的每张表编写对应的model.dao.mapping,虽然很简单,但是工作量很大,所以通常会使用代码生成器Mybatis-Generator帮我们自 ...
- Tsung运行环境安装(转)
转自:http://www.cnblogs.com/tsbc/p/4272974.html#_Toc372013359 tsung Tsung运行环境安装 检查安装一下依赖包,以免在安装的时候报错.( ...
- windows下LIB和DLL的区别与使用
共有两种库: 一种是LIB包含了函数所在的DLL文件和文件中函数位置的信息(入口),代码由运行时加载在进程空间中的DLL提供,称为动态链接库dynamic link library. 一种是LIB包含 ...
- C++求两个数的最大值
//不使用if,:?等推断语句.求两个数字中最大的那个数字. #include<iostream> using namespace std; int main() { int a = -1 ...
- Windows7清除图标缓存
以下是批处理文件代码: rem 关闭Windows外壳程序explorer taskkill /f /im explorer.exe rem 清理系统图标缓存数据库 attrib -h -s -r & ...
- ICSharpCode.SharpZipLib工具压缩与解压缩zip文件
using System; using System.Collections.Generic; using System.IO; using System.Text; using ICSharpCod ...
- string.Format字符串格式化说明
1.格式化货币(跟系统的环境有关,中文系统默认格式化人民币,英文系统格式化美元) string.Format("{0:C}",0.2) 结果为:¥0.20 (英文操作系统结果:$0 ...
- PHP 5.3以上版本推荐使用mysqlnd驱动
什么是mysqlnd?mysqldnd(MySQL native driver)是由PHP源码提供的mysql驱动连接代码.它的目的是代替旧的libmysql驱动. 传统的安装php的方式中,我们在编 ...