summaryrefslogtreecommitdiffstats
path: root/documentation/advanced/advanced-spring.asciidoc
blob: 54e0f895c175b866fd1e9174b5824373f5c553d2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
---
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.github.io/spring-tutorial/[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.github.io/spring-tutorial/[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. Pick Vaadin as
a dependency on the site to include all the required Vaadin Spring dependencies
and auto-configuration.The generated project is a Spring application stub; you
need to add at least a UI class to the generated project.

See the link:https://vaadin.github.io/spring-tutorial/[Vaadin Spring
Tutorial] for detailed instructions for using Spring Boot.


[[advanced.spring.installation]]
== Installing Vaadin Spring Add-on

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 link:https://vaadin.com/directory#addon/vaadin-spring[vaadin.com/directory#addon/vaadin-spring]
or link:https://vaadin.com/directory#addon/vaadin-spring-boot[vaadin.com/directory#addon/vaadin-spring-boot].
See <<../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"]
----
    &lt;dependency org="com.vaadin" name="vaadin-spring"
                rev="[replaceable]##latest.release##"/&gt;
----
The Maven dependency is as follows:

[subs="normal"]
----
    &lt;dependency&gt;
        &lt;groupId&gt;com.vaadin&lt;/groupId&gt;
        &lt;artifactId&gt;vaadin-spring&lt;/artifactId&gt;
        &lt;version&gt;[replaceable]##LATEST##&lt;/version&gt;
    &lt;/dependency&gt;
----

For Vaadin Spring Boot, depending on [literal]#++vaadin-spring-boot-starter++# will
include all the required Vaadin dependencies.


[[advanced.spring.preparing]]
== Preparing Application for Spring

A Vaadin application that uses Spring must have a file named
[filename]#applicationContext.xml# in the [filename]#WEB-INF# directory.
Using Spring Initializr automatically generates a suitable file, but if
you configure Vaadin Spring manually, you can follow the model below.

[subs="verbatim,replacements,quotes"]
----
&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;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"&gt;

  &lt;!-- Configuration object --&gt;
  &lt;bean class="[replaceable]#com.example.myapp.MySpringUI.MyConfiguration#" /&gt;

  &lt;!-- Location for automatically scanned beans --&gt;
  &lt;context:component-scan
      base-package="[replaceable]#com.example.myapp.domain#" /&gt;
&lt;/beans&gt;
----
The application should not have a servlet extending [classname]#VaadinServlet#,
as Vaadin servlet has its own [classname]#SpringVaadinServlet# 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
<<../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 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
<<advanced-navigator#advanced.navigator,"Navigating
in an Application">>. It manages Spring views with a special view provider and
enables view scoping. Furthermore, Vaadin Spring provides a customized navigator class
[classname]#SpringNavigator# that supports the scope functionality.


[[advanced.spring.navigation.ui]]
=== Preparing the UI

You can define navigation for any single-component container, component container or bean
implementing [classname]#ViewDisplay#, as described in
<<advanced-navigator#advanced.navigator.navigating,"Setting
Up for Navigation">>, but typically you set up navigation for the entire UI
content. The easiest way to set up navigation is to use the annotation
[classname]#@SpringViewDisplay# on the UI (in which case the whole contents of the UI are
replaced on navigation) or on any UI scoped bean implementing one of the above mentioned
interfaces.


[source, java]
----
@SpringUI(path="/myspringui")
@SpringViewDisplay
public class MySpringUI extends UI {
    @Override
    protected void init(VaadinRequest request) {
    }
}
----

If not using Spring Boot, auto-configuration of navigation can be enabled with the annotation
@EnableVaadinNavigation on a configuration class.


[[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.

+
You can also navigate to a view 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.

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

If access to a view is denied by an access control bean, the access denied view
is shown for it. For non-existing views, the error view is shown. You can set
up an "Access Denied" view that is shown if the access is denied with
[methodname]#setAccessDeniedViewClass()# in [classname]#SpringViewProvider#,
and an error view with [methodname]#setErrorView()# in [classname]#SpringNavigator#.
The same view can also be used both as an access denied view and as an error
view to hide the existence of views the user is not allowed to access.


[source, java]
----
@Autowired
SpringViewProvider viewProvider;
@Autowired
SpringNavigator navigator;

@Override
protected void init(VaadinRequest request) {
    // Set up access denied view
    viewProvider.setAccessDeniedViewClass(
        MyAccessDeniedView.class);
    // Set up error view
    navigator.setErrorView(MyErrorView.class);
----

Note that the error view can also be a class with which an error view bean is
found. In this case, the error view must be UI scoped.


[[advanced.spring.deployment]]
== Deploying Spring UIs and Servlets

Vaadin Spring hooks into Vaadin framework by using a special
[classname]#SpringVaadinServlet#. 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
<<../application/application-lifecycle#application.lifecycle.servlet-service,"Vaadin
Servlet, Portlet, and Service">>, you simply need to extend
[classname]#com.vaadin.spring.server.SpringVaadinServlet# 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
<<../application/application-environment#application.environment,"Deploying
an Application">>.


[[advanced.spring.deployment.urlmapping]]
=== Defining Servlet Root

Spring UIs are managed by a Spring servlet ( [classname]#SpringVaadinServlet#),
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]#SpringVaadinServlet# 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"]
----
&lt;web-app&gt;
  ...
  &lt;servlet&gt;
    &lt;servlet-name&gt;Default&lt;/servlet-name&gt;
    &lt;servlet-class&gt;
      com.vaadin.spring.server.SpringVaadinServlet
    &lt;/servlet-class&gt;
  &lt;/servlet&gt;

  &lt;servlet-mapping&gt;
    &lt;servlet-name&gt;Default&lt;/servlet-name&gt;
    &lt;url-pattern&gt;[replaceable]##/myspringuis/*##&lt;/url-pattern&gt;
  &lt;/servlet-mapping&gt;

  &lt;servlet-mapping&gt;
    &lt;servlet-name&gt;Default&lt;/servlet-name&gt;
    &lt;url-pattern&gt;/VAADIN/+++*+++&lt;/url-pattern&gt;
  &lt;/servlet-mapping&gt;
&lt;/web-app&gt;
----

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")))