diff options
author | elmot <elmot@vaadin.com> | 2015-09-25 16:40:44 +0300 |
---|---|---|
committer | elmot <elmot@vaadin.com> | 2015-09-25 16:40:44 +0300 |
commit | a1b265c318dbda4a213cec930785b81e4c0f7d2b (patch) | |
tree | b149daf5a4f50b4f6446c906047cf86495fe0433 /documentation/advanced/advanced-spring.asciidoc | |
parent | b9743a48a1bd0394f19c54ee938c6395a80f3cd8 (diff) | |
download | vaadin-framework-a1b265c318dbda4a213cec930785b81e4c0f7d2b.tar.gz vaadin-framework-a1b265c318dbda4a213cec930785b81e4c0f7d2b.zip |
Framework documentation IN
Change-Id: I767477c1fc3745f9e1f58075fe30c9ac8da63581
Diffstat (limited to 'documentation/advanced/advanced-spring.asciidoc')
-rw-r--r-- | documentation/advanced/advanced-spring.asciidoc | 696 |
1 files changed, 696 insertions, 0 deletions
diff --git a/documentation/advanced/advanced-spring.asciidoc b/documentation/advanced/advanced-spring.asciidoc new file mode 100644 index 0000000000..7f83b864fd --- /dev/null +++ b/documentation/advanced/advanced-spring.asciidoc @@ -0,0 +1,696 @@ +--- +title: Vaadin Spring Add-on +order: 18 +layout: page +--- + +[[advanced.spring]] += Vaadin Spring Add-on + +((("Vaadin Spring", id="term.advanced.spring.springlong", range="startofrange"))) + + +((("Spring", id="term.advanced.spring.spring", range="startofrange"))) + + +Vaadin Spring and Vaadin Spring Boot add-ons make it easier to use Spring in +Vaadin applications. Vaadin Spring enables Spring dependency injection with +custom UI and view providers, and provides three custom scopes: +[classname]#UIScope#, [classname]#ViewScope#, and +[classname]#VaadinSessionScope#. + +API documentation for add-ons is available at: + +* Vaadin Spring API at link:https://vaadin.com/api/vaadin-spring[vaadin.com/api/vaadin-spring] +* Vaadin Spring Boot API at link:https://vaadin.com/api/vaadin-spring-boot[vaadin.com/api/vaadin-spring-boot] + +To learn more about Vaadin Spring, the +link:https://vaadin.com/wiki/-/wiki/Main/Vaadin+Spring[Vaadin Spring Tutorial] +gives a hands-on introduction. The source code of the Spring Tutorial demo is +available for browsing or cloning at +link:https://github.com/Vaadin/spring-tutorial[github.com/Vaadin/spring-tutorial]. + +[[advanced.spring.spring]] +== Spring Overview + +__Spring Framework__ is a Java application framework that provides many useful +services for building applications, such as authentication, authorization, data +access, messaging, testing, and so forth. In the Spring core, one of the central +features is dependency injection, which accomplishes inversion of control for +dependency management in managed beans. Other Spring features rely on it +extensively. As such, Spring offers capabilities similar to CDI, but with +integration with other Spring services. Spring is well-suited for applications +where Vaadin provides the UI layer and Spring is used for other aspects of the +application logic. + +__Spring Boot__ is a Spring application development tool that allows creating +Spring applications easily. __Vaadin Spring Boot__ builds on Spring Boot to +allow creating Vaadin Spring applications easily. It starts up a servlet, +handles the configuration of the application context, registers a UI provider, +and so forth. + +Regarding general Spring topics, we recommend the following Spring +documentation: + +ifdef::web[] +* link:http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/[Spring +Framework Reference Documentation]. + +* link:http://projects.spring.io/spring-framework/[Spring Project] + +* link:https://vaadin.com/wiki/-/wiki/Main/Vaadin+Spring[Vaadin Spring Tutorial] + +endif::web[] + +[[advanced.spring.spring.injection]] +=== Dependency Injection + +__Dependency injection__ is a way to pass dependencies (service objects) to +dependent objects (clients) by injecting them in member variables or initializer +parameters, instead of managing the lifecycle in the clients or passing them +explicitly as parameters. In Spring, injection of a service object to a client +is configured with the [classname]#@Autowired# annotation. + +For a very typical example in a web application, you could have a user data +object associated with a user session: + + +[source, java] +---- +@SpringComponent +@VaadinSessionScope +public class User implements Serializable { + private String name; + + public void setName(String name) {this.name = name;} + public String getName() {return name;} +} +---- + +The [classname]#@SpringComponent# annotation allows for automatic detection of +managed beans by Spring. (The annotation is exactly the same as the regular +Spring [classname]#@Component#, but has been given an alias, because Vaadin has +a [interfacename]#Component# interface, which can cause trouble.) + +Now, if we have a UI view that depends on user data, we could inject the data in +the client as follows: + + +[source, java] +---- +public class MainView extends CustomComponent implements View { + User user; + Label greeting = new Label(); + + @Autowired + public MainView(User user) { + this.user = user; + ... + } + + ... + @Override + public void enter(ViewChangeEvent event) { + // Then you can use the injected data + // for some purpose + greeting.setValue("Hello, " + user.getName()); + } +} +---- + +Here, we injected the user object in the constructor. The user object would be +created automatically when the view is created, with all such references +referring to the same shared instance in the scope of the Vaadin user session. + + +[[advanced.spring.spring.contexts]] +=== Contexts and Scopes + +__Contexts__ in Spring are services that manage the lifecycle of objects and +handle their injection. Generally speaking, a context is a situation in which an +instance is used with a unique identity. Such objects are essentially +"singletons" in the context. While conventional singletons are application-wide, +objects managed by a Spring container can be "singletons" in a more narrow +__scope__: a user session, a particular UI instance associated with the session, +a view within the UI, or even just a single request. Such a context defines the +lifecycle of the object: its creation, use, and finally its destruction. + +Earlier, we introduced a user class defined as session-scoped: + + +[source, java] +---- +@SpringComponent +@VaadinSessionScope +public class User { +---- + +Now, when you need to refer to the user, you can use Spring injection to inject +the session-scoped "singleton" to a member variable or a constructor parameter; +the former in the following: + + +[source, java] +---- +public class MainView extends CustomComponent implements View { + @Autowired + User user; + + Label greeting = new Label(); + ... + + @Override + public void enter(ViewChangeEvent event) { + greeting.setValue("Hello, " + user.getName()); + } +} +---- + + + +[[advanced.spring.boot]] +== Quick Start with Vaadin Spring Boot + +The Vaadin Spring Boot is an add-on that allows for easily creating a project +that uses Vaadin Spring. It is meant to be used together with Spring Boot, which +enables general Spring functionalities in a web application. + +You can use the Spring Initializr at +link:https://start.spring.io/[start.spring.io] website to generate a project, +which you can then download as a package and import in your IDE. The generated +project is a Spring application stub; you need to add at least Vaadin +dependencies ( [literal]#++vaadin-spring-boot++#, [literal]#++vaadin-themes++#, +and [literal]#++vaadin-client-compiled++#) and a UI class to the generated +project, as well as a theme, and so forth. + +See the link:https://vaadin.com/wiki/-/wiki/Main/Vaadin+Spring[Vaadin Spring +Tutorial] for detailed instructions for using Spring Boot. + + +[[advanced.spring.installation]] +== Installing Vaadin Spring Add-on + +Vaadin Spring requires a Java EE 7 compatible servlet container, such as +Glassfish or Apache TomEE Web Profile, as mentioned for the reference toolchain +in +<<dummy/../../../framework/getting-started/getting-started-environment#getting-started.environment,"Setting +up the Development Environment">>. + +To install the Vaadin Spring and/or Vaadin Spring Boot add-ons, either define +them as an Ivy or Maven dependency or download from the Vaadin Directory add-on +page at <<,vaadin.com/directory#addon/vaadin-spring>> or +<<,vaadin.com/directory#addon/vaadin-spring-boot>>. See +<<dummy/../../../framework/addons/addons-overview.asciidoc#addons.overview,"Using +Vaadin Add-ons">> for general instructions for installing and using Vaadin +add-ons. + +The Ivy dependency is as follows: + +[subs="normal"] +---- + <dependency org="com.vaadin" name="vaadin-spring" + rev="[replaceable]#latest.release#"/> +---- +The Maven dependency is as follows: + +[subs="normal"] +---- + <dependency> + <groupId>com.vaadin</groupId> + <artifactId>vaadin-spring</artifactId> + <version>[replaceable]#LATEST#</version> + </dependency> +---- + +[[advanced.spring.peparing]] +== Preparing Application for Spring + +A Vaadin application that uses Spring must have a file named +[filename]#applicationContext.xml# in the [filename]#WEB-INF# directory. + +[subs="normal"] +---- +<?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.xsd + http://www.springframework.org/schema/context + http://www.springframework.org/schema/context/spring-context-4.1.xsd"> + + //Configuration object + + <bean class="[replaceable]#com.example.myapp.MySpringUI.MyConfiguration#" /> + + //Location for automatically scanned beans + + <context:component-scan + base-package="[replaceable]#com.example.myapp.domain#" /> +</beans> +---- +The application should not have a servlet extending [classname]#VaadinServlet#, +as Vaadin servlet has its own [classname]#VaadinSpringServlet# that is deployed +automatically. If you need multiple servlets or need to customize the Vaadin +Spring servlet, see <<advanced.spring.deployment>>. + +You can configure managed beans explicitly in the file, or configure them to be +scanned using the annotations, which is the preferred way described in this +section. + + +[[advanced.spring.springui]] +== Injecting a UI with [classname]#@SpringUI# + +((("[classname]#@SpringUI#", id="term.advanced.spring.springui", range="startofrange"))) + + +Vaadin Spring offers an easier way to instantiate UIs and to define the URL +mapping for them than the usual ways described in +<<dummy/../../../framework/application/application-environment#application.environment,"Deploying +an Application">>. It is also needed for enabling Spring features in the UI. To +define a UI class that should be instantiated for a given URL, you simply need +to annotate the class with [classname]#@SpringUI#. It takes an optional path as +parameter. + + +[source, java] +---- +@SpringUI(path="/myniceui") +@Theme("valo") +public class MyNiceUI extends UI { + ... +---- + +The path in the URL for accessing the UI consists of the context path of the +application and the UI path, for example, [literal]#++/myapp/myniceui++#. Giving +empty UI path maps the UI to the root of the application context, for example, +[literal]#++/myapp++#. + + +[source, java] +---- +@SpringUI +---- + +See <<advanced.spring.deployment>> for how to handle servlet URL mapping of +Spring UIs when working with multiple servlets in the same web application. + +(((range="endofrange", startref="term.advanced.spring.springui"))) + +[[advanced.spring.scopes]] +== Scopes + +((("Spring", "scopes", id="term.advanced.spring.scopes", range="startofrange"))) + + +As in programming languages, where a variable name refers to a unique object +within the scope of the variable, an object has unique identity within a scope +in Spring. However, instead of identifying the objects by variable names, they +are identified by their type (object class) and any qualifiers they may have. + +The scope of an object can be defined with an annotation to the class as +follows: + + +[source, java] +---- +@VaadinSessionScope +public class User { + ... +---- + +Defining a scope in Spring is normally done with the [classname]#@Scope# +annotation. For example, [literal]#++@Scope("prototype")++# creates a new +instance every time one is requested/auto-wired. Such standard scopes can be +used with some limitations. For example, Spring session and request scopes do +not work in background threads and with certain push transport modes. + +Vaadin Spring provides three scopes useful in Vaadin applications: a session +scope, a UI scope, a view scope, all defined in the +[package]#com.vaadin.spring.annotation# package. + +[[advanced.spring.scopes.session]] +=== [classname]#@VaadinSessionScope# + +The session scope is the broadest of the custom scopes defined in Vaadin Spring. +Objects in the Vaadin session scope are unique in a user session, and shared +between all UIs open in the session. This is the most basic scope in Vaadin +applications, useful for accessing data for the user associated with the +session. It is also useful when updating UIs from a background thread, as in +those cases the UI access is locked on the session and also data should be in +that scope. + + +[[advanced.spring.scopes.ui]] +=== [classname]#@UIScope# + +UI-scoped beans are uniquely identified within a UI instance, that is, a browser +window or tab. The lifecycle of UI-scoped beans is bound between to the +initialization and closing of a UI. Whenever you inject a bean, as long as you +are within the same UI, you will get the same instance. + +Annotating a Spring view (annotated with [classname]#@SpringView# as described +later) also as [classname]#@UIScoped# makes the view retain the same instance +when the user navigates away and back to the view. + + +[[advanced.spring.scopes.view]] +=== [classname]#@ViewScope# + +The annotation enables the view scope in a bean. The lifecycle of such a bean +starts when the user navigates to a view referring to the object and ends when +the user navigates out of the view (or when the UI is closed or expires). + +Views themselves are by default view-scoped, so a new instance is created every +time the user navigates to the view. + + +(((range="endofrange", startref="term.advanced.spring.scopes"))) + +ifdef::web[] +[[advanced.spring.navigation]] +== View Navigation + +Vaadin Spring extends the navigation framework in Vaadin, described in +<<dummy/../../../framework/advanced/advanced-navigator#advanced.navigator,"Navigating +in an Application">>. It manages Spring views with a special view provider and +enables view scoping. + +[[advanced.spring.navigation.ui]] +=== Preparing the UI + +You can define navigation for any single-component container, as described in +<<dummy/../../../framework/advanced/advanced-navigator#advanced.navigator.navigating,"Setting +Up for Navigation">>, but typically you set up navigation for the entire UI +content. To use Vaadin Spring views, you need to inject a +[classname]#SpringViewProvider# in the UI and add it as a provider for the +navigator. + + +[source, java] +---- +@SpringUI(path="/myspringui") +public class MySpringUI extends UI { + @Autowired + SpringViewProvider viewProvider; + + @Override + protected void init(VaadinRequest request) { + Navigator navigator = new Navigator(this, this); + navigator.addProvider(viewProvider); + + // Navigate to start view + navigator.navigateTo(""); + } +} +---- + + +[[advanced.spring.navigation.view]] +=== The View + +A view managed by Vaadin Spring only needs to have the [classname]#@SpringView# +annotation, which registers the view in the [classname]#SpringViewProvider#. The +annotation is also necessary to enable Spring features in the view, such as +injection. + + +[source, java] +---- +@SpringView(name=MainView.NAME) +public class MainView extends CustomComponent implements View { + public static final String NAME = "main"; + ... +---- + +The annotation can have the following optional paramers: + +name (optional):: Specifies the path by which the view can be accessed programmatically and by the +URI fragment. + + ++ +[source, java] +---- +@SpringView(name="main") +---- ++ +If the view name is not given, it is derived from the class name by removing a +possible "View" suffix, making it lower case, and using a dash ("-") to separate +words originally denoted by capital letters. Thereby, a view class such as +[classname]#MyFunnyView# would have name " [literal]#++my-funny++#". + ++ +It is a recommended pattern to have the view name in a static member constant in +the view class, as was done in the example previously, so that the name can be +referred to safely. + +supportsParameters:: Specifies whether view parameters can be passed to the view as a suffix to the +name in the navigation state, that is, in the form of +[literal]#++viewname+viewparameters++#. The view name is merely a prefix and +there is no separator nor format for the parameters, but those are left for the +view to handle. The parameter support mode is disabled by default. + + ++ +[source, java] +---- +@SpringView(name="myview", supportsParameters=true) +---- ++ +You could then navigate to the state with a URI fragment such as +[literal]#++#!myview/someparameter++# or programmatically with: + + ++ +[source, java] +---- +getUI().getNavigator().navigateTo("myview/someparameter"); +---- ++ +The [methodname]#enter()# method of the view gets the URI fragment as parameter +as is and can interpret it in any application-defined way. + ++ +Note that in this mode, matching a navigation state to a view is done by the +prefix of the fragment! Thereby, no other views may start with the name of the +view as prefix. For example, if the view name is " [literal]#++main++#", you +must not have a view named " [literal]#++maintenance++#". + +uis:: If the application has multiple UIs that use [classname]#SpringViewProvider#, +you can use this parameter to specify which UIs can show the view. + + ++ +[source, java] +---- +@SpringView(name="myview", uis={MySpringUI.class}) +---- ++ +If the list contains [parameter]#UI.class#, the view is available to all UIs. + + ++ +[source, java] +---- +@SpringView(name="myview", uis={UI.class}) +---- + + +In the following, we have a login view that accesses a session-scoped user +object. Here, we use a constant to define the view name, so that we can use the +constant when navigating to it. + + +[source, java] +---- +@SpringView(name=LoginView.NAME) +public class LoginView extends CustomComponent + implements View { + public final static String NAME = ""; + + // Here we inject to the constructor and actually do + // not store the injected object to use it later + @Autowired + public LoginView(User user) { + VerticalLayout layout = new VerticalLayout(); + + // An input field for editing injected data + BeanItem<User> item = new BeanItem<User>(user); + TextField username = new TextField("User name", + item.getItemProperty("name")); + username.setNullRepresentation(""); + layout.addComponent(username); + + // Login button (authentication omitted) / Java 8 + layout.addComponent(new Button("Login", e -> + getUI().getNavigator(). + navigateTo(MainView.VIEWNAME))); + + setCompositionRoot(layout); + } + + @Override + public void enter(ViewChangeEvent event) {} +} +---- + +You could now navigate to the view from any other view in the UI with: + + +[source, java] +---- +getUI().getNavigator().navigateTo(LoginView.VIEWNAME); +---- + + +endif::web[] + +[[advanced.spring.accesscontrol]] +== Access Control + +Access control for views can be implemented by registering beans implementing +[interfacename]#ViewAccessControl# or +[interfacename]#ViewInstanceAccessControl#, which can restrict access to the +view either before or after a view instance is created. + +Integration with authorization solutions, such as Spring Security, is provided +by additional unofficial add-ons on top of Vaadin Spring. + +[[advanced.spring.accesscontrol.accessdenied]] +=== Access Denied View + +By default, the view provider acts as if a denied view didn't exist. You can set +up an "Access Denied" view that is shown if the access is denied with +[methodname]#setAccessDeniedView()# in [classname]#SpringViewProvider#. + + +[source, java] +---- +@Autowired +SpringViewProvider viewProvider; + +@Override +protected void init(VaadinRequest request) { + Navigator navigator = new Navigator(this, this); + navigator.addProvider(viewProvider); + + // Set up access denied view + viewProvider.setAccessDeniedViewClass( + MyAccessDeniedView.class); +---- + + + +[[advanced.spring.deployment]] +== Deploying Spring UIs and Servlets + +Vaadin Spring hooks into Vaadin framework by using a special +[classname]#VaadinSpringServlet#. As described earlier, you do not need to map +an URL path to a UI, as it is handled by Vaadin Spring. However, in the +following, we go through some cases where you need to customize the servlet or +use Spring with non-Spring servlets and UIs in a web application. + +[[advanced.spring.servlets.custom]] +=== Custom Servlets + +When customizing the Vaadin servlet, as outlined in +<<dummy/../../../framework/application/application-lifecycle#application.lifecycle.servlet-service,"Vaadin +Servlet, Portlet, and Service">>, you simply need to extend +[classname]#com.vaadin.spring.internal.VaadinSpringServlet# instead of +[classname]#com.vaadin.servlet.VaadinServlet#. + +[subs="normal"] +---- +@WebServlet(value = "[replaceable]#/*#", asyncSupported = true) +public class [replaceable]#MySpringServlet# extends SpringVaadinServlet { +} +---- +The custom servlet must not have [classname]#@VaadinServletConfiguration#, as +you would normally with a Vaadin servlet, as described in +<<dummy/../../../framework/application/application-environment#application.environment,"Deploying +an Application">>. + + +[[advanced.spring.deployment.urlmapping]] +=== Defining Servlet Root + +Spring UIs are managed by a Spring servlet ( [classname]#VaadinSpringServlet#), +which is by default mapped to the root of the application context. For example, +if the name of a Spring UI is " [literal]#++my-spring-ui++#" and application +context is [literal]#++/myproject++#, the UI would by default have URL " +[literal]#++/myproject/my-spring-ui++#". If you do not want to have the servlet +mapped to context root, you can use a [classname]#@WebServlet# annotation for +the servlet or a [filename]#web.xml# definition to map all Spring UIs to a +sub-path. + +For example, if we have a root UI and another: + +[subs="normal"] +---- +@SpringUI(path=[replaceable]#""#) // At Spring servlet root +public class [replaceable]#MySpringRootUI# extends UI {...} + +@SpringUI("[replaceable]#another#") +public class [replaceable]#AnotherUI# extends UI {...} +---- +Then define a path for the servlet by defining a custom servlet: + +[subs="normal"] +---- +@WebServlet(value = "[replaceable]#/myspringuis/*#", asyncSupported = true) +public class [replaceable]#MySpringServlet# extends SpringVaadinServlet { +} +---- +These two UIs would have URLs /myproject/myspringuis and +/myproject/myspringuis/another, respectively. + +You can also map the Spring servlet to another URL in servlet definition in +[filename]#web.xml#, as described the following. + + +[[advanced.spring.servlets.mixing]] +=== Mixing With Other Servlets + +The [classname]#VaadinSpringServlet# is normally used as the default servlet, +but if you have other servlets in the application, such as for non-Spring UIs, +you need to define the Spring servlet explicitly in the [filename]#web.xml#. You +can map the servlet to any URL path, but perhaps typically, you define it as the +default servlet as follows, and map the other servlets to other URL paths: + +[subs="normal"] +---- +<web-app> + ... + + <servlet> + <servlet-name>Default</servlet-name> + <servlet-class> + com.vaadin.spring.internal.VaadinSpringServlet + </servlet-class> + </servlet> + + <servlet-mapping> + <servlet-name>Default</servlet-name> + <url-pattern>[replaceable]#/myspringuis/*#</url-pattern> + </servlet-mapping> + + <servlet-mapping> + <servlet-name>Default</servlet-name> + <url-pattern>/VAADIN/*</url-pattern> + </servlet-mapping> +</web-app> +---- +With such a setting, paths to Spring UIs would have base path +[filename]#/myapp/myspringuis#, to which the (optional) UI path would be +appended. The [filename]#/VAADIN/*# only needs to be mapped to the servlet if +there are no other Vaadin servlets. + + + +(((range="endofrange", startref="term.advanced.spring.springlong"))) +(((range="endofrange", startref="term.advanced.spring.spring"))) + + |