Spring"
(5 intermediate revisions by the same user not shown) | |||
Line 29: | Line 29: | ||
− | To integrate ZK application | + | To integrate ZK application with Spring, the minimal configuration you have to setup is the following: |
'''Spring related configuration in web.xml''' | '''Spring related configuration in web.xml''' | ||
<source lang='xml'> | <source lang='xml'> | ||
− | |||
<!-- Loads the Spring application context configuration --> | <!-- Loads the Spring application context configuration --> | ||
<listener> | <listener> | ||
Line 42: | Line 41: | ||
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class> | <listener-class>org.springframework.web.context.request.RequestContextListener</listener-class> | ||
</listener> | </listener> | ||
− | |||
</source> | </source> | ||
Line 66: | Line 64: | ||
</beans> | </beans> | ||
</source> | </source> | ||
− | * Line 12: Apply <code>@Component</code> on those classes that you plan to register them as Spring beans and specify base package of those classes. | + | * Line 12: Apply <code>@Component</code> on those classes that you plan to register them as Spring beans and specify the base package of those classes. |
= Access a Spring Bean in a ZUL = | = Access a Spring Bean in a ZUL = | ||
− | ZUL provides a feature called [[ZK Developer's Reference/UI Composing/ZUML/EL Expressions#Variable Resolver| variable resolver]] that allows users to access Spring bean using EL expressions. | + | ZUL provides a feature called [[ZK Developer's Reference/UI Composing/ZUML/EL Expressions#Variable Resolver| variable resolver]] that allows users to access Spring bean using EL expressions. Simply put the below directive on top of a ZUML page: |
'''<code><?variable-resolver class="org.zkoss.zkplus.spring.DelegatingVariableResolver" ?></code> ''' | '''<code><?variable-resolver class="org.zkoss.zkplus.spring.DelegatingVariableResolver" ?></code> ''' | ||
− | Then, | + | Then, on the rest of your page, you can access a Spring-Managed bean directly using its '''bean id'''. |
− | Assume that we have | + | Assume that we have 2 beans: |
<source lang="java"> | <source lang="java"> | ||
Line 86: | Line 84: | ||
} | } | ||
</source> | </source> | ||
− | * User preference should be distinct for each user but shared among multiple requests. It is suitable to be a session scoped bean. | + | * User preference should be distinct for each user but shared among multiple requests. It is suitable to be a session-scoped bean. |
Line 119: | Line 117: | ||
= Wire a Spring Bean = | = Wire a Spring Bean = | ||
+ | It is a very common requirement that we need a Spring bean in a composer, e.g. calling an authentication bean to do login. You can inject Spring beans into ZK Composer/ViewModel in the following ways. | ||
== Spring's @Autowire == | == Spring's @Autowire == | ||
− | ZK stores a Composer/ViewModel as a component's attribute, and you can dynamically add/remove components at any time. If you want a fresh new state of a component when each time you add/create it, you should declare a Composer/ViewModel in <code>prototype</code> scoped. Then you can use <code>@Autowire</code> to wire Spring beans | + | ZK stores a Composer/ViewModel as a component's attribute, and you can dynamically add/remove components at any time. If you want a fresh new state of a component when each time you add/create it, you should declare a Composer/ViewModel in <code>prototype</code> scoped. Then you can use <code>@Autowire</code> to wire Spring beans into a Composer/ViewModel. |
<!-- | <!-- | ||
− | this section might have problems. injecting a singleton service bean (longer- | + | this section might have problems. injecting a singleton service bean (longer-lived) into a composer (shorter-lived) should not need a proxy. |
+ | We need to test it under clustering env. | ||
== Using Scoped-Proxy == | == Using Scoped-Proxy == | ||
Line 141: | Line 141: | ||
--> | --> | ||
+ | |||
== Wire a Spring bean in a Composer == | == Wire a Spring bean in a Composer == | ||
− | + | Alternatively, ZK provides another way to wire a Spring bean to a composer which is not a Spring-managed bean. When we apply a <code>SelectorComposer</code> to a ZUL with <code>org.zkoss.zkplus.spring.DelegatingVariableResolver</code> mentioned in the previous section, we can apply annotation, <code>@WireVariable</code> on a variable we want to wire a Spring bean with. ZK will then wire the corresponding Spring bean on the variable using a variable name that's the same as the bean's name. Or, you can specify the bean's name with <code>@WireVariable("beanName")</code>. | |
− | |||
− | |||
− | Alternatively, ZK provides another way to wire a Spring bean to a composer which is not a Spring-managed bean. When we apply a | ||
'''A composer that wires Spring beans''' | '''A composer that wires Spring beans''' | ||
− | <source lang="java" highlight="3"> | + | <source lang="java" highlight="1, 3"> |
− | |||
public class ResolverComposer extends SelectorComposer<Window> { | public class ResolverComposer extends SelectorComposer<Window> { | ||
Line 167: | Line 164: | ||
} | } | ||
</source> | </source> | ||
+ | * Line 1: <code>@WireVariable("beanName")</code> only works inside a <code>SelectorComposer</code>. | ||
+ | |||
'''A ZUL with Spring variable resolver''' | '''A ZUL with Spring variable resolver''' | ||
Line 188: | Line 187: | ||
@WireVariable | @WireVariable | ||
− | OrderService orderService; | + | private OrderService orderService; |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
... | ... | ||
} | } |
Latest revision as of 03:20, 18 January 2023
Overview
Spring Framework is a popular application development framework for enterprise Java. One key element is its infrastructural support: a light-weighted container that manages POJOs as Spring beans and maintain beans' dependency injection relationship. We will talk about several integration ways including wiring and accessing beans in various conditions. We assume that readers have knowledge in Spring's basic configuration and concept such as bean scope, we will therefore not cover these topics here. Please refer to Spring documentation.
Configuration
The minimal Maven dependency you need is :
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
Note: If you don't use Maven, please refer to Spring Framework Reference Documentation to know which JAR file you need.
To integrate ZK application with Spring, the minimal configuration you have to setup is the following:
Spring related configuration in web.xml
<!-- Loads the Spring application context configuration -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- For using web scoped bean -->
<listener>
<listener-class>org.springframework.web.context.request.RequestContextListener</listener-class>
</listener>
You can enable Spring's classpath scanning to register beans.
WEB-INF/applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<!-- Scans for application @Components to deploy -->
<context:component-scan base-package="org.zkoss.reference.developer" />
</beans>
- Line 12: Apply
@Component
on those classes that you plan to register them as Spring beans and specify the base package of those classes.
Access a Spring Bean in a ZUL
ZUL provides a feature called variable resolver that allows users to access Spring bean using EL expressions. Simply put the below directive on top of a ZUML page:
<?variable-resolver class="org.zkoss.zkplus.spring.DelegatingVariableResolver" ?>
Then, on the rest of your page, you can access a Spring-Managed bean directly using its bean id.
Assume that we have 2 beans:
@Component
@Scope("session")
public class UserPreference {
...
}
- User preference should be distinct for each user but shared among multiple requests. It is suitable to be a session-scoped bean.
@Component
public class SystemConfiguration {
...
}
- As system configuration should be shared within the whole application, this should be a singleton bean.
Access Spring beans with EL
<?variable-resolver class="org.zkoss.zkplus.spring.DelegatingVariableResolver"?>
<window title="Access Bean with different scopes" border="normal" width="700px"
apply="org.zkoss.reference.developer.composer.ResolverComposer">
<vlayout>
<hlayout>
User Preference :
<label id="sessionValue">${userPreference.value}</label>
</hlayout>
<hlayout>
System Configuration :
<label id="singletonValue">${systemConfiguration.value}</label>
</hlayout>
</vlayout>
</window>
- The delegating variable-resolver will look-up the bean named
userPreference
automatically for you.
Wire a Spring Bean
It is a very common requirement that we need a Spring bean in a composer, e.g. calling an authentication bean to do login. You can inject Spring beans into ZK Composer/ViewModel in the following ways.
Spring's @Autowire
ZK stores a Composer/ViewModel as a component's attribute, and you can dynamically add/remove components at any time. If you want a fresh new state of a component when each time you add/create it, you should declare a Composer/ViewModel in prototype
scoped. Then you can use @Autowire
to wire Spring beans into a Composer/ViewModel.
Wire a Spring bean in a Composer
Alternatively, ZK provides another way to wire a Spring bean to a composer which is not a Spring-managed bean. When we apply a SelectorComposer
to a ZUL with org.zkoss.zkplus.spring.DelegatingVariableResolver
mentioned in the previous section, we can apply annotation, @WireVariable
on a variable we want to wire a Spring bean with. ZK will then wire the corresponding Spring bean on the variable using a variable name that's the same as the bean's name. Or, you can specify the bean's name with @WireVariable("beanName")
.
A composer that wires Spring beans
public class ResolverComposer extends SelectorComposer<Window> {
@WireVariable
private OrderService orderService;
@Wire("#number")
private Label label;
@Override
public void doAfterCompose(Window comp) throws Exception {
super.doAfterCompose(comp);
label.setValue(Integer.toString(orderService.list().size()));
}
}
- Line 1:
@WireVariable("beanName")
only works inside aSelectorComposer
.
A ZUL with Spring variable resolver
<?variable-resolver class="org.zkoss.zkplus.spring.DelegatingVariableResolver"?>
<window title="Access Bean with different scopes" border="normal" width="700px"
apply="org.zkoss.reference.developer.spring.composer.ResolverComposer">
...
</window>
Wire a Spring bean in a ViewModel
Wiring a Spring bean in a ViewModel is very similar to the case in a composer, simply apply @WireVariable
with variable resolver. In the example below we put variable resolver in a zul with a directive.
A ViewModel that wires a Spring bean
public class OrderVM {
@WireVariable
private OrderService orderService;
...
}
The zul uses OrderVM with a Spring variable resolver
<?variable-resolver class="org.zkoss.zkplus.spring.DelegatingVariableResolver"?>
<zk>
<window title="Order Management" border="normal" width="600px" apply="org.zkoss.bind.BindComposer"
viewModel="@id('vm') @init('org.zkoss.reference.developer.spring.order.viewmodel.OrderVM')"
validationMessages="@id('vmsgs')">
...
</window>
</zk>
Adding Variable Resolver to a Composer/ViewModel
Adding a variable resolver to a ZUL will make it available to all composers on the ZUL. If you want to add a variable resolver to a specific composer (or ViewModel) only, you should apply the annotation
@VariableResolver(org.zkoss.zkplus.spring.DelegatingVariableResolver.class)
on the class that inherits SelectorComposer
or a ViewModel. Then, apply @WireVariable
on variables like we did in the previous section.
Example code are as follows:
@VariableResolver(org.zkoss.zkplus.spring.DelegatingVariableResolver.class)
public class SpringComposer extends SelectorComposer<Window> {
@WireVariable
private OrderService orderService;
...
}
Retrieve a Spring Bean Programmatically
org.zkoss.zkplus.spring.SpringUtil
is a utility class that allows you to get Spring-managed beans by their name in Java.
public class SpringComposer extends SelectorComposer<Window> {
@Wire("#number")
private Label label;
@Override
public void doAfterCompose(Window comp) throws Exception {
super.doAfterCompose(comp);
OrderService orderService = (OrderService)SpringUtil.getBean("orderService");
label.setValue(Integer.toString(orderService.list().size()));
}
}
Integrate Spring Webflow and Security
ZK also provides integration to other Spring projects such as Spring Security and Spring Webflow with ZK Spring. Please refer to ZK Spring Essentials for details.
Example Source Code
You can get all source code mentioned in this chapter at GitHub/zkoss/zkbooks.