spring笔记



Spring首先是一个轻量级的容器,是一个非侵入性的框架,实现了控制翻转,提供对AOP概念的实现;
以及对持久层、事务的支持;提供MVC Web框架的实现,并对于一些常用的企业服务API提供一致的编程模型,
另外对于现存的常用的框架,提供了整合方案;


容器:可以管理对象的生成、销毁、资源的获取等生命周期,甚至建立对象与对象之间的依赖关系;


控制翻转:依赖关系的转移,控制权的转移,实现应该依赖于抽象,抽象不应该依赖实现;


ApplicationContext的实现类:FileSystemXmlApplicationContext、ClassPathXmlApplicationContext、XmlWebApplicationContext;


<import>标签:
<import>标签必须放置在<bean>标签之前,定义文件必须放置在同一个目录或是ClassPath之中,以相对路径指定Bean定义文件的位置,
每个定义文件的内容都必需包括<beans>根标签;
<beans ...>
<import resource="dao-config.xml"/>
<bean id="" class=""/>
</beans>


别名
<bean id="dataSource" class=""/>
<alias name="dataSource" alias="app:dataSource"/>

<bean id="dataSource" name="app:dataSource,user:dataSource" class=""/>


bean的实例化:
<bean id="" class=""/>

静态工厂方式一:
<bean id="musicBox" class="com.tt.MusicBoxFactory"
factory-method="createMusicBox"/>

静态工厂方式二:
<bean id="musicBox"
factory-bean="musicBoxFactory"
factory-method="createMusicBox"/>

Bean的scope
在Spring中,从BeanFactory或ApplicationContext取得的实例被默认为singleton,也就是默认每一个Bean名称只维持一个实例。
使用Singleton模式产生单一实例,对单线程的程序来说没什么问题,但对于多线程的程序,必须注意到线程安全的问题,
防止多个线程同时存取公用资源所引发的资料不同步问题,通常Singleton的Bean都是无状态的(Stateless);


Spring中设置,每次从BeanFactory或APplicationContext指定别名并取得Bean时都产生一个新的实例:
<bean id="helloBean"
class="com.tt.HelloBean"
scope="prototype"
或scope="singleton"/>

Bean的生命周期:
Bean的建立:由BeanFactory读取bean定义文件,并生成各个Bean实例;
属性注入:执行相关的Bean属性依赖注入;
BeanNameAware的setBeanName():如果Bean类有实现BeanNameAware接口,则执行它的setBeanName()方法;
BeanFactoryAware的setBeanFactory:如果bean类有实现BeanFactoryAware接口,则执行它的setBeanFactory()方法;
(如果由ApplicationContext读取bean定义文件,ApplicationContextAware的setApplicationContext():如果bean类有实现ApplicationContextAware接口,则执行它的setApplicationContext()方法;)
BeanPostProcessors的postProcessBeforeInitialization():如果有任何的BeanPost实例与Bean的实例关联,则执行BeanPostProcessors的processBeforeInitialization()方法;
InitializingBean的afterPropertiesSet():如果bean类有实现InitializingBean,则执行它的afterPropertiesSet()方法;
Bean定义文件中定义init-method:如果有以下配置,当代码运行至这个阶段时,就会执行initBean()方法;
<bean id="" class=""
init-method="initBean"/>
BeanPostProcessor的postProcessaAfterInitialization():如果有任何的BeanPostProcessors实例与Bean实例关联,则执行BeanPostProcessors实例的processaAfterInitialization()方法;
DisposableBean的destroy():在容器关闭时,如果bean类有实现DisposableBean接口,则执行它的destroy()方法;
Bean定义文件中定义destroy-method:在容器关闭时,可以在bean定义文件使用"destroy-method"属性设置方法名称,当代码运行至这个阶段时,就会执行destroyBean()方法;
<bean id="" class=""
destroy-method="destroyBean"/>

init-method与afterPropertiesSet()、destroy-method与destroy()意义相同;

Bean定义的继承:
<bean id="parentBean" abstract="true">
...
</bean>


<bean id="sonBean" class="" parent="parentBean">
...
</bean>


bean的依赖设置:
<bean id="" class="">
<constructor-arg index="0">
<value>test</value>
</constructor-arg>
...
</bean>


自动绑定
<bean id="" class=""
autowire="byType"
或autowire="byName"
或autowire="constructor"
或autowire="autodetect">
...
</bean>
autodetect:先constructor,再byType;


集合
<bean id="" class="">
<property name="">
<list>
<value>test</value>
</list>
<set>
<value>test</value>
</set>
<map>
<entry key="ttkey">test</entrty>
</map>
</property>
</bean>


Lookup Method Injection
指定使用某个bean的方法,产生新的对象并进行注入;
<bean id="sysMessage" class="" scope="prototype">
<bean id="messageManager" class="">
<lookup-method name="createMessage" bean="sysMessage"/>
</bean>


Aware接口:BeanNameAware、BeanFactoryAware、ApplicationContextAware
BeanNameAware:在设置依赖关系后、初始化方法前,设置bean的名称:setBeanName(String baenName);
BeanFactoryAware、ApplicationContextAware类似上;


BeanPostProcessor、BeanFactoryPostProcessor、
BeanPostProcessor
在bean的依赖关系由Spring容器建立并设置后,通过实现BeanPostProcessor接口,还有机会自定义一些bean的修正动作来修正相关的属性;
public interface BeanPostProcessor{
public Object postProcessBeforeInitialization(Object bean, String name)throws BeansException;
public Object postProcessAfterInitialization(Object bean, String name)throws BeansException;
}


BeanFactoryPostProcessor
在BeanFactory载入bean定义文件的所有内容,但还没正式产生Bean实例之前,可以对该beanFactory进行一些处理,方法是让bean类实现BeanFactoryPostProcessor接口;
public interface BeanFactoryPostProcessor{
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)throws BeansException;
}
假设有一个SomeClass实现BeanFactoryPostProcessor接口,则可以在Bean定义文件中定义:
<bean id="someClass" class="">
...
</bean>
使用ApplicationContext时,若在bean定义文件中定义了实现BeanFactoryPostProcessor接口的类,则applicationContext会自动使用这些类的实例;


Spring中提供了几个BeanFactoryPostProcessor接口的实现类:PropertyPlaceholderConfigurer、PropertyOverrideConfigurer、CustomEditorConfigurer;
PropertyPlaceholderConfigurer,通过这个类可以让xml定义文件引用.properties文件的信息;
<bean id="configBean" class="...PropertyPlaceholderConfigurer">
<property name="location" value="hello.properties"/>
或<property name="locations">
<list>
<value>hello1.properties</value>
<value>hello2.properties</value>
</list>
</property>
</bean>
<bean id="helloBean" class="">
<property name="helloword" value="${onlyfun.helloWord}"/>
</bean>


PropertyOverrideConfigurer
通过这个类,可以在.properties中设置一些优先的属性,当有重复时,优先使用这个文件中的值;


CustomEditorConfigurer
将字符串值转换为指定对像;


ApplicationContext是基于BeanFactory建立的,除了具备BeanFactory基本的容器管理功能外,还支持更多应用程序框架的特性,
像资源的获取、消息解析、事件的监听和传播;

资源的获取
Resource resource = context.getResource("classPath:admin.properties");


解析文字:国际化
<bean id="messageSource" class="...ResourceBundleMessageSource">
<property name="basename" value="messages"/>
</bean>
messages_zh_TW.properties:userLogin=用户{0}于{1}登陆
Object[] args = new Object[]{"良葛格", Calendar.getInstance().getTime()};
context.getMessage("userLogin", args, defaultMessage, Locale.US);


监听事件
ApplicationEvent的实现类:
ContextClosedEvent:在ApplicationContext关闭时发布事件;
ContextRefreshedEvent:在ApplicationContext初始或refresh发布事件;
RequestHandledEvent:在web应用中,当请求处理时,ApplicationContext会发布此事件;


监听器
ApplicationListener实现类:
ConsoleListener:仅在debug时使用,会在文字模式下显示记录ApplicationContext的相关消息;
PerformanceMonitorListener:在web应用中,搭配webApplicationContext使用,可记录请求的回应时间;


事件传播:context.publishEvent(new ContextClosedEvent(context));




AOP


Advices
Before Advice:MethodBeforeAdvice before(Method method, Object[] args, Object target);
After Advice:AfterReturningAdvice afterReturning(Object returnValue, Method method, Object[] args, Object target);
Around Advice:MethodInterceptor invoke(MethodInvocation methodInvocation);
Throw Advice:ThrowsAdvice afterThrowing([Method], [args], [target], subclassOfThrowable);


<bean id="helloProxy" class="org...ProxyFactoryBean">
<property name="proxyInterfaces" value="com.test.IHello"/>
<property name="target" ref="helloSpeaker"/>
<property name="interceptorNames">
<list>
<value>logBeforeAdvice</value>
</list>
</property>
</bean>


Pintcut、Advisor
NameMatchMethodPointcutAdvisor、RegExpMethodPointcutAdvisor
<bean id="helloAdvisor" class="org...NameMatchMethodPointcutAdvisor">
<property name="mappedName" value="*Newbie"/>
<property name="advice" ref="logBeforeAdvice"/>
</bean>


<bean id="helloAdvisor" class="org...RegExpMethodPointcutAdvisor">
<property name="pattern" value=".*Newbie"/>
<property name="advice" ref="logBeforeAdvice"/>
</bean>


<bean id="helloProxy" class="org...ProxyFactoryBean">
<property name="proxyInterfaces" value="com.test.IHello"/>
<property name="target" ref="helloSpeaker"/>
<property name="interceptorNames">
<list>
<value>helloAdvisor</value>
</list>
</property>
</bean>


ControlFlowPointcut:判断在方法的执行堆栈中,某个指定类的某方法是否曾要求目标对象执行某个动作;
<bean id="helloFlowControlPointcut" class="org...ControlFlowPointcut">
<constructor-arg value="com.test.Some"/>
</bean>


<bean id="helloAdvisor" class="org...DefaultPointcutAdvisor">
<property name="pointcut" ref="helloFlowControlPointcut"/>
<property name="advice" ref="logBeforeAdvice"/>
</bean>


<bean id="helloProxy" class="org...ProxyFactoryBean">
<property name="proxyInterfaces" vlaue="com.test.IHello"/>
<property name="target" ref="helloSpeaker"/>
<property name="interceptorNames">
<list>
<value>helloAdvisor</value>
</list>
</property>
</bean>


Pointcut接口


Introduction:为对象动态地加入行为、属性;
IntroductionInterceptor(DelegatingIntroductionInterceptor是它的实现类,可以动态地添加属性、行为)
public class OtherIntroduction implements IntroductionInterceptor, IOther{
//Class类的isAssignableFrom(Class cls)方法,如果调用这个方法的类或接口与参数cls表示的类或接口相同,
//或者是参数cls表示的类或接口的父类,则返回true
public boolean implementsInterface(Class clazz){
return clazz.isAssignableFrom(IOther.class);
}

public Object invoke(MethodInvocation methodInvocation){
if(implementsInterface(methodInvocation.getMethod().getDeclaringClass())){
return methodInvocation.getMethod().invoke(this, methodInvocation.getArguments());
}else{
return methodInvocation.proceed();
}
}

public void doOther(){
...
}
}


<bean id="otherIntroduction" class="com.test.OtherIntroduction"/>


<bean id="otherAdvisor" class="org...DefaultIntroductionAdvisor">
<constructor-arg ref="otherIntroduction"/>
<constructor-arg value="com.test.IOther"/>
</bean>


<bean id="proxyFactoryBean" class="org...ProxyFactoryBean">
...
</bean>
(IOther)some).doOther();


DelegatingIntroductionInterceptor
<bean id="lockAdvisor" class="org...DefaultIntroductionAdvisor">
<constructor-arg ref="lockIntroduction"/>
<constructor-arg vlaue="com.test.ILockable"/>
</bean>


JDBC封装
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
jdbcTemplate.queryForList(sql, args);
jdbcTemplate.queryForObject(sql, args);
jdbcTemplate.update(sql, args);


jdbcTemplate.execute("create table...");


jdbcTemplate.query("select...", new Object[]{id}, new RowCallbackHandler(){
public void processRow(ResultSet rs){
user.setId(new Integer(rs.getInt("id")));
}
})


JDBC事务管理


事务的4个特性:
原子性:事务中的各个操作不可分割。
一致性:违反约束则回滚到原来状态。
隔离性:并发访问,不破坏数据的正确性和完整性。
持久性:数据的固化。


数据操作的三种不确定情况:
脏读取:一个事务读取了另一个并行事务未提交的数据。
不可重复读:一个事务再次读取之前曾读取过的数据时,发现该数据已经被另一个已提交的事务修改。
虚读/幻读:一个事务重新执行一个查询,返回一套符合查询条件的记录,但这些记录中包含了因为其他最近提交的事务而产生的新记录。


隔离层级:脏读、不可重复读、幻读;
ISOLATION_DEFAULT:使用底层数据库预设的隔离层级;
ISOLATION_READ_UNCOMMITTED:允许事务读取其他并行的事务还没送出的数据,会发生脏读、不可重复读、幻读等问题;
ISOLATION_READ_COMMITTED:允许事务读取其他并行的事务已经送出的数据字段,可以防止脏读问题;
ISOLATION_REPEATABLE_READ:要求多次读取的数据必须相同,除非事务本身更新数据,可防止脏读、不可重复读等问题;
ISOLATION_SERIALIZABLE:完全的隔离层级,可防止脏读、不可重复读、幻读等问题,会锁定对应的数据表格,因而有效率问题;


传播行为:
PROPAGATION_MANDATORY:方法必需在一个现存的事务中进行,否则丢出异常;
PROPAGATION_NESTED:在一个嵌入的事务中进行,如果不是,丢出异常;
PROPAGATION_NEVER:不应在事务中进行,如果有就丢出异常;
PROPAGATION_SUPPORTS:支持现在的事务,如果没有就以非事务的方式执行;
PROPAGATION_NOT_SUPPORTED:不应在事务中进行,如果有就暂停现存的事务;
PROPAGATION_REQUIRED:支持现在的事务,如果没有就建立一个新的事务;
PROPAGATION_REQUIRES_NEW:建立一个新的事务,如果现存一个事务就暂停它;


Spring对事务管理的抽象关键在于PlatformTransactionManager


编程式事务管理、声明式事务管理


编程式事务可以使用PlatformTransactionManager、TransactionTemplate实现;
PlatformTransactionManager的实现类DataSourceTransactionManager
transactionManager = new DataSourceTransactionManager(dataSource);
DefaultTransactionDefinition def = new DefaultTransactionDefinition();
def.setPropagationBehavior(TransactionDefinition.PROPAGTION_REQUIRED);
def.setIsolationLevel(TransactionDefinition.ISOLATION_REPEATABLE_READ);


TransactionStatus status = transactionManager.getTransaction(defaultTransactionDefinition);
...
transactionManager.commit(status);
transactionManager.rollback(status);


TransactionTemplate
transactionTemplate.execute(new TransactionCallback(){
public Object doInTransaction(TransactionStatus status){
return jdbcTemplate.update("insert into user (name) values ('test')");
}
})


JDBC声明式事务管理
TransactionProxyFactoryBean
<bean id="transactionManager" class="org...DataSourceTransactionManager">
<property name="datasSource" ref="dataSource"/>
</bean>


<bean id="userDAOProxy" class="org...TransactionProxyFactoryBean">
<property name="proxyInterface">
<list>
<value>com.test.IUserDAO</value>
</list>
</property>
<property name="target" ref="userDAO"/>
<property name="transactionManager" ref="transactionManager"/>
<property name="transactionAttributes">
<props>
<prop key="insert*">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>

<bean id="transactionInterceptor" class="org...TransactionInterceptor">
<property name="transactionManager" ref="transactionManager"/>
<property name="transactionAttributeSource" value="com.test.UserDAO.insert*=PROPAGATION_REQUIRED"/>
</bean>


<bean id="userDAOProxy" class="org...ProxyFactoryBean">
<property name="proxyInterfaces">
<list>
<value>com.test.IUserDAO</value>
</list>
</property>
<property name="target" ref="userDAO"/>
<property name="intereceptorNames">
<list>
<value>transactioninterceptor</value>
</list>
</property>
</bean>


Spring与Hibernate整合
将sessionFactory注入:
<bean id="sessionFactory" class="org...LocalSessionFactoryBean"
destroy-method="close">
<property name="dataSource" ref="dataSource"/>

<property name="mappingResources">或mappingDirectoryLocations:一次性指定某个文件夹下所有的xml文件
<list>
<value>com/test/User.hbm.xml</value>
</list>
</property>

<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org...MySQLDialect</prop>
</props>
</properties>
</bean>


HibernateTemplate
hibernateTemplate = new HibernateTemplate(sessionFactory);
hibernateTemplate.execute(new HibernateCallback(){
public Object doInHibernate(Session session)throws HibernateException{
return session.load(User.class);
}
});


public class UserDAO extends HibernateDaoSupport implements IUserDAO{
public ovid insert(User user){
getHibernateTemplate().save(user);
}
}


如果使用hibernateTemplate.load()方法,将会用到session的load()方法,这将会使用Hibernate3默认的延迟加载功能,
但HibernateTemplate执行完load()方法后,会直接关闭session,因而此时若再尝试取得User的属性,将会发生LazyInitializationException;
解决办法之一,是实现HibernateCallback接口,并将实例传入给HibernateTemplate的execute()方法:
public User find(final Integer id){
User user = (User)hibernateTemplate.execute(
new HibernateCallback(){
public Object doInHibernate(Session session)throws HibernateException, SQLException{
User user = (User)session.load(User.class, id);
Hibernate.initialize(user);
return user;
}
}
);
}
另一个方法在.hbm.xml中设置lazy为false;


HibernateTemplate的Lob支持;


Hibernate编程事务管理
transactionTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
transactionTemplate.execute(
new TransactionCallbackWithoutResult(){
protected void doInTransactionWithoutResult(TransactionStatus status){
hibernateTemplate.save(userData);
}
}
);


Hibernate声明式事务
<bean id="transactionManager" class="org...HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<bean id="userDAOProxy" class="org...TransactionProxyFactoryBean">
<property name="proxyInterfaces">
<list>
<value>com.test.IUserDAO</value>
</list>
</property>
<property name="target" ref="userDAO"/>
<property name="transactionManager" ref="transactionManager"/>
<property name="transactionAttributes">
<props>
<prop key="insert">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>




Spring MVC


<servlet>
<servlet-name>dispatcherServlet</servlet-name>
<servlet-class>org...DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/mvc-config.xml</param-value>
</init-param>
</servlet>


<bean id="viewResolver" class="org...InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>


WebApplicationContext
如果想要在自己所定义的servlet中使用Spring的容器功能,可以使用ContextLoaderListener:
<listener>
<listener-class>
org...ContextLoaderListener
</listener>
</listener>
默认读取applicationContext.xml文件
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/beans-config.xml,/WEB-INF/demo-service.xml</param-value>
</context-param>


WebApplicationContext是ApplicationContext的子类
WebApplicationContext ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(this.getServletContext());
Date date = (Date)ctx.getBean("dateBean");


在不支持Listener设置的容器上,可以使用ContextLoaderServlet
<servlet>
<servlet-name>contextLoader</servlet-name>
<servlet-class>org...ContextLoaderServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>


Handler Mapping
默认BeanNameUrlHandlerMapping


<bean id="urlHandlerMapping" class="org...SimpleUrlHandlerMapping">
<property name="mappings">
<props>
<prop key="/hello.do">helloController</prop>
<prop key="/hello.do">helloController</prop>
</props>
</property>
</bean>


Handler Interceptor
public interface HandlerInterceptor{
boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception;
void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)throws Exception;
void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)throws Exception;
}
<bean id="urlHandlerMapping" class="org...SimpleUrlHandlerMapping">
<property name="interceptors">
<list>
<ref bean="loggingHandlerInterceptor"/>
</list>
</property>
</bean>


Controller继承架构
abstractController
MultiActionController、BaseCommandController
AbstractCommandController、AbstractFormController
SimpleFormController、AbstractWizardFormController
ParameterizableViewController


ModelAndView(View, String modelName, Object model)
默认为Forward
View子类:RedirectView、InternalResourceView、TilesView


Exception Resolver
在jsp网页或Servlet在运行过程中丢出了异常,而想捕捉这个异常,除了使用容器与jsp网页中有关异常的捕捉设置方法外
(例如设置web.xml的<error-page>标签,或是在jsp网页"page"指令元素的"errorPage"属性),也可以在DispatcherServlet
的定义文件中设置处理错误网页,即设置一个ExceptionResolver的Bean实例。
<bean id="exceptionResolver" class="org...SimpleMappingExceptionResolver">
<props>
<prop key="java.sql.SQLException">sqlexception</prop>
<prop key="java.sql.IOException">ioexception</prop>
</props>
</bean>


MultiActionController、ParameterMethodNameResolver(默认的为InternalPathMethodNameResolver,根据所给的网址,判断执行哪个方法);
<bean id="paraMethodResolver" class="org...ParamterMethodNameResolver">
<property name="paramName" value="action"/>
<property name="defaultMethodName" value="list"/>
</bean>
<bean id="bookController" class="com.test.BookController">
<property name="methodNameResolver" ref="paraMethodResolver"/>
<property name="testPage" value="test"/>
</bean>

<bean id="bookDelegate" class="com.test.BookDelegate">
<property name="testPage" value="test"/>
</bean>
<bean id="bookController" class="com.test.BookController">
<property name="methodNameResolver" ref="paraMethodResolver"/>
<property name="delegate" value="bookDelegate"/>
</bean>
delegate中的方法必需有request、response


ParameterizableViewController
<bean id="indexController" class="org...ParameterizableViewController">
<property name="viewName" value="index"/>
</bean>


AbstractFormController
1、执行formBackingObject()方法,要回传一个commandClass的实例;
2、执行initBinder()方法,允许对command的特定field作格式化动作;
protected void initBinder(HttpServletRequest request,
ServletRequestDataBinder binder) throws Exception {
binder.registerCustomEditor(java.util.Date.class, new CustomDateEditor(
new SimpleDateFormat("yyyy-MM-dd"), true));}
3、执行showFrom(),返回一个view对象,用于表单展现;
4、如果"bindOnNewForm"属性被设置为true,则应用ServletRequestDataBinder根据初始请求参数来填入一个新的表单对象,
并执行onBindOnNewForm()方法;
5、showForm()方法会执行referenceData()方法,如果在展现表单的过程中,需要一些相关数据,可以回传一个Map对象;
6、Model对象被展现,用户可以看到表单并进行填写;
用户填写完表单之后发送出表单,将会依以下的流程进行;
1、如果不向用POST这样的方式来判断用户是否送出表单,可以重新定义isFormSubmission()方法;
2、如果sessionForm属性没有设置,则会执行formBackingObject()方法以取得表单对象,否则尝试从session中取得表单对象,
   如果没有找到则执行handleInvalidSubmit()方法,默认的动作是尝试建立新的表单对象并重新填写表单;
3、ServletRequestDataBinder根据目前的请求参数填入表单对象;
4、执行onBind()方法,在绑定数据之后、验证数据之前可以对表单对象进行一些自制的修改动作。
5、如果"validateOnBinding"属性被设置,则使用验证器。
6、执行onBindAndValidate()方法,允许在验证数据之后对表单对象做一些处理;
7、表单对象处理完毕,最后执行processFormSubmission()方法,子类要重新定义这个方法,以完成用户的请求;


SimpleFormController
1、执行processFormSubmission()以检验Errors对象,看看在绑定或验证时有无任何的错误;
2、如果有错误发生,回传formView所设置的页面;
3、如果isFormChangeRequest()根据request被重新定义并回传true,则也会回到formView,在回到formView之前会执行onFormChange(),
   让您有机会修正表单对象;
4、如果没有错误发送,则会执行onSubmit(request, response, command, BindException);


ThrowawayController
scope="singleton"


validator
errors.rejectValue("password", "less-than-four", null, "密码不得小于4个字符");


PropertyEditor
子类PropertyEditorSupport


文件上传
MultipartResolver
子类:CommonsMultipartResolver、CosMultipartResolver
<bean id="multipartResolver" class="org...CommonsMultipartResolver">
<property name="maxUploadSize" value="10000000"></property>
</bean>
binder.registCustomEditor(byte[].class, new ByteArrayMultipartFileEditor());


<spring:bind>
<spring:bind path="command.*">
${status.errorMessage}
</spring:bind>
<spring:bind path="command.userName">
<input type="text" name="${status.expression}" value="${status.value}">
<c:forEach items="${status.errorMessages}">
<c:out vlaue="${error}"/>
</c:forEach>
</spring:bind>


国际化
<spring:message code="welcome" arguments="Justin,Lin"/>


<form:form commandName="loginForm">
名称:<form:input path="userName"/>
密码:<form:password path="password"/>
</form:form>


邮件整合
JavaSenderImpl senderImpl = new JavaMailSenderImpl();
JavaMailSenderImpl senderImpl = new JavaMailSenderImpl();
senderImpl.setHost("your_mail_server.com");
SimpleMailMessage mailMessage = new SimpleMailMessage();
mailMessage.setTo("xxx@you_mail_server.com");
mailMessage.setFrom("xxx@you_mail_server.com");
mailMessage.setSubject("test");
mailMessage.setText("this is my test!");
senderImpl.send(mailMessage);


HTML mail
MimeMessage mailMessage = senderImpl.createMimeMessage();
MimeMessageHelper messageHelper = new MimeMessageHelper(mailMessage);
messageHelper.setTo("");
messageHelper.setFrom("");
messageHelper.setSubject("");
messageHelper.setText("<html>...</html>");
senderImpl.send(mailMessage);


定时任务
Quartz
可以继承QuartzJobBean
<bean id="jobDetailBean" class="org...JobDetailBean">
<property name="jobClass" value="com.test.DemoJob"/>
<property name="jobDataAsMap">
<map>
<entry key="jobData" value-ref="someData"/>
</map>
</property>
</bean>
<bean id="simpleTriggerBean" class="org...SimpleTriggerBean">
<property name="jobDetail" ref="jobDetailBean"/>
<property name="repeatInterval" value="5000"/>
<property name="startDelay" value="1000"/>
</bean>

<bean id="conTriggerBean" class="org...ConTriggerBean">
<property name="jobDetail" ref="jobDetailBean"/>
<property name="cronExpression" value="0 0 19 * * ?"/>
</bean>
<bean id="schedulerFactoryBean" class="org...SchedulerFactoryBean">
<property name="triggers">
<list>
<ref bean="simpleTriggerBean"/>
</list>
</property>
</bean>


croExpression
秒 分 小时 每月第几天 月 每星期第几天 年
有好几个时间点:",":"0 0 10,12,14 * * ?";
连续的时间:"-":"0 0 10-15 * ?";


MethodInvokingJobDetailFactoryBean
直接指定执行某个对象的方法
<bean id="jobDetailBean" class="org...MethodInvokingJobDetailFactoryBean">
<property name="targetObject" ref="someJob"/>
<property name="targetMethod" value="execute"/>
</bean>
<bean id="cronTriggerBean" class="org...CronTriggerBean">
<property name="jobDetail" ref="jobDetailBean"/>
<property name="cronExpression value="0 30 18 * * ?"/>
</bean>
<bean id="schedulerFactoryBean" class="org...SchedulerFactoryBean">
<property name="triggers">
<list>
<ref bean="cronTriggerBean"/>
</list>
</property>
</bean>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值