Liferay Portal – Spring MVC portlets – Ext JS

feelingmomInternet and Web Development

Dec 7, 2013 (3 years and 9 months ago)

105 views

 
Liferay  Portal  

 
Spring  MVC  portlets
 

 
Ext  JS
 
Florent  Garit
 
Table  des  matières
 
Disclaimer
 
................................
................................
................................
................................
................................
........
 
3
 
1.  Liferay  Portal
 
................................
................................
................................
................................
................................
 
4
 
1.1.  Install
 
Liferay
 
................................
................................
................................
................................
.........................
 
4
 
1.2.  Get  started
 
................................
................................
................................
................................
............................
 
4
 
1.3.  Add  pages
 
................................
................................
................................
................................
.............................
 
4
 
1.4.  Configure  portlets
 
................................
................................
................................
................................
.................
 
5
 
2.  Lif
eray  General  Configuration
 
................................
................................
................................
................................
......
 
6
 
2.1.  Main  configuration  file
 
................................
................................
................................
................................
.........
 
6
 
2.2.  Chat  Portlet  

 
Annoying  Ajax  requests
 
................................
................................
................................
.................
 
6
 
3.  Create  a  new  Spring  MVC
 
Liferay  Portlet  project  using  Liferay  IDE  Tools  for  Eclipse  and  Liferay  Plugins  SDK
 
...........
 
7
 
3.1.  Installation
 
................................
................................
................................
................................
............................
 
7
 
3.2.  Create  a  new  Eclipse  Project
 
................................
................................
................................
................................
.
 
7
 
3.3.  Modify  it  to  work  with  Spring  MVC
 
................................
................................
................................
.......................
 
7
 
3.4.  How  to  configure  Liferay
-­‐
display.xml
 
................................
................................
................................
...................
 
8
 
3.5.  How  to  configure  Liferay
-­‐
portlet.xml
 
................................
................................
................................
...................
 
8
 
3.1.  Web.xml
 
................................
................................
................................
................................
................................
 
9
 
3.2.  Portlet.xml
 
................................
................................
................................
................................
............................
 
9
 
3.3.  Lastly,  [portlet
-­‐
name]
-­‐
portlet.xml
 
................................
................................
................................
......................
 
10
 
3.4.  Make  it  work
 
................................
................................
................................
................................
.......................
 
11
 
4.  Develop  portlets  for  Liferay  using  Spring  MVC
 
................................
................................
................................
..........
 
12
 
4.1.  Introduction
 
................................
................................
................................
................................
........................
 
12
 
4.2.  Useful  links
 
................................
................................
................................
................................
..........................
 
12
 
4.3.  Sprin
g  MVC  principle
 
................................
................................
................................
................................
..........
 
13
 
4.4.  Dependency  Injection
 
................................
................................
................................
................................
.........
 
13
 
4.5.  Mapping
 
................................
................................
................................
................................
..............................
 
14
 
4.5.1.  RenderMapping
 
................................
................................
................................
................................
...........
 
14
 
4.5.2.  ActionMapping
 
................................
................................
................................
................................
.............
 
15
 
4.6.  Pas
s  Model  Data  to  a  view
 
................................
................................
................................
................................
..
 
16
 
4.6.1.  Using  the  annotation  @ModelAttribute
 
................................
................................
................................
......
 
16
 
4.6.2.  Using  the  ModelMap  bean
 
................................
................................
................................
..........................
 
16
 
4.7.  RequestParam
 
................................
................................
................................
................................
.....................
 
17
 
4.8.  Display  a  list  of  objects  with  actions
 
................................
................................
................................
...................
 
17
 
 
4.1.  Forms
 
................................
................................
................................
................................
................................
..
 
19
 
4.1.1.  Very  basic  form
 
................................
................................
................................
................................
............
 
19
 
4.1.2.  More  advanced  form
 
................................
................................
................................
................................
...
 
20
 
4.1.3.  
CustomValidators
 
................................
................................
................................
................................
.........
 
21
 
4.2.  Do  Ajax
 
................................
................................
................................
................................
................................
 
23
 
5.  Make  Portlets,  tips
 
................................
................................
................................
................................
.....................
 
25
 
5.1.  Init  and  destroy  methods  of  a  component
 
................................
................................
................................
.........
 
25
 
5.2.  Get  Context  Path  
-­‐
 
client  side  technology.
 
................................
................................
................................
..........
 
25
 
5.3.  access  renderRequest,  renderResponse  in  jsp
 
................................
................................
................................
...
 
25
 
5.4.  Get  Portlet  Context  and  Context  Real  Path
 

 
server  side
 
................................
................................
...................
 
25
 
5.5.  Access  static  resources
 
................................
................................
................................
................................
.......
 
25
 
5.6.  messages.properties  files
 
................................
................................
................................
................................
...
 
26
 
5.7.  Edit  Mode  and  Preferences
 
................................
................................
................................
................................
 
26
 
5.7.1.  What  preferences  are
 
................................
................................
................................
................................
..
 
26
 
5.7.2.  Help  with  preferences
 
................................
................................
................................
................................
..
 
26
 
5.7.3.  Enable  edit  mode  and  configure  preferences
 
................................
................................
..............................
 
26
 
5.7.4.  Access  edit  mode  in  Liferay
 
................................
................................
................................
.........................
 
26
 
5.7.5.  Portlet  Preferences
 
................................
................................
................................
................................
......
 
26
 
5.8.  
Minifier  

 
lots  of  .js  files  in  tomcat/temp/minifier/…
 
................................
................................
.........................
 
27
 
6.  HSQL  Database
 
................................
................................
................................
................................
..........................
 
28
 
6.1.  Exploring  Liferay’s  HSQL  Database
 
................................
................................
................................
.....................
 
28
 
6.2.  Create  a  new  HSQL  Database
 
................................
................................
................................
.............................
 
28
 
6.3.  Launch  a  HSQL  Server
 
................................
................................
................................
................................
.........
 
29
 
6.4.  Connect  to  a  HSQL  database  from  a  Spring  MVC  application
 
................................
................................
.............
 
29
 
7.  Use  Ext  JS  in  a  portlet
 
................................
................................
................................
................................
................
 
30
 
7.
1.  Introduction
 
................................
................................
................................
................................
........................
 
30
 
7.2.  Installation
 
................................
................................
................................
................................
..........................
 
30
 
7.3.  Use  Ext  JS  into  a  portlet
 
................................
................................
................................
................................
......
 
30
 
7.4.  Architecture  of  an  Ext  Js  application
 
................................
................................
................................
...................
 
30
 
7.5.  Change  the  content  of  a  dom  element
 
................................
................................
................................
...............
 
31
 
7.6.  Important  thing  to  know  about  javascript  objects
 
................................
................................
.............................
 
31
 
7.7.  What’s  a  Ext.data.store
?
 
................................
................................
................................
................................
.....
 
32
 
7.8.  Ajax  Requests
 
................................
................................
................................
................................
......................
 
32
 
7.9.  JSON
 
................................
................................
................................
................................
................................
....
 
33
 
 
 
 
 
 
Disclaimer
 
 
There  is  no  guarantee  that  the  methods  I  describe  in  this  documentation  are  correct  in  every  way.  
There  might  be  
better  ways  to  do  things.  This  is  all  ba
sed  on  my  
experience
 
building  a  Liferay  Portal  and  Spring  MVC  portlets  to  put  
in  it.  I  was  new  to  both  Liferay  and  Spring  MVC  when  I  started  this.
 
In  short,
 
some  things  may  not  work  perfectly  and  
others  could  
probably
 
have  done  differently.
 
 
1.  
Liferay  Portal
 
1.1.

 
Install  Liferay
 
Useful  links:
 
-­‐

The  portal  comes  bundled  with  an  example  site  preinstalled,  here  is  how  to  remove  it:  
http://www.liferay.com/community/wiki/
-­‐
/wiki/Main/7Cogs+sample+data
 
-­‐

Quick  installation  guide:  
http://www.liferay.com/web/guest/community/wiki/
-­‐
/wiki/Main/Quick%20Installation%20Instructions
 
-­‐

Database  configuration
 
(to  use  MySQL  for  instance):  
http://www.liferay.com/community/wiki/
-­‐
/wiki/Main/Database+Configuration#section
-­‐
Database+Configuration
-­‐
Liferay5.2
 
1.2.

Get  started
 
To  log  in  as  admin,  the  
login
 
is:  
test@liferay.com
 
and  the  
password  
is:  test.  You  might  want  to  change  it  later.
 
When  it  is  done,  at  the  top  of  the  page  you  will  find  a  toolbar.
 
 
-­‐

The  
Add
 
drop  down  menu
 
is  useful  for  adding  portlet  to  pages.
 
-­‐

The  
Manage
 
drop  down  menu
 
shows  you  some  
Administration  actions
.
 
-­‐

The  
Toggle  Edit  Controls
 
button  shows  or  hides  buttons  such  as  X  crosses  in  the  top  left  hand  corner  of  a  
portlet.
 
 
Click  
Manage
 
then  
Control  Panel
.
 
I  don’t  exactly  remember  how  it  is  when  you  just  set  up  the  portal,  but  I  think  the
re  is  already  a  community  created.  
It  acts  like  the  main  community.  Some  important  settings  can  be  set  by  going  to  
Control  Panel  >  Portal  Section  >  
Portal  Settings
.
 
Then  you  can  add  other  communities  of  users  with  their  own  public  and  private  pages  (
Contro
l  Panel  >  Portal  
Section  >  Communities
).
 
 
Once  it  is  done,  you  can  add  pages  and  add  portlets  to  them.
 
1.3.

Add  pages
 
First,  you  should  create  a  template  for  all  pages  (
Control  Panel  >  Portal  Section  >  Page  Templates
).  Then  when  you  
create  a  page,  choose  this  t
emplate.  There  is  probably  a  way  to  force  a  template  to  be  used  every  time  you  create  a  
page,  but  I  didn’t  have  time  to  look  into  that.
 
I  do  know  that  it  is  possible  to  create  custom  templates  with  css  or  other  languages.
 
 
To  add  pages,  you  can  either  do  i
t  from  the  user  side  of  the  website  while  connected  as  Admin.
 
Or  you  can  go  to  the  
Control  Panel
.  Select  the  
main  community
 
(it  should  display  the  name  you  gave  it)  in  the  
second  section  of  the  left  menu  (in  between  the  
Section  about  your  account
 
and  the  
P
ortal  Section
).  Then  go  to  
Pages.  From  there  you  can  
edit  settings  about  the  page
 
(such  as  the  link  to  get  there  etc…)  and  
add  pages
,  then  
pages  to  pages  and  so  on…  Use  the  tabs  to  do  so.
 
 
To  add  portlets  to  a  page,  click  the  
Add
 
button  from  the  
top  
toolbar  menu
 
and  then  click  
More…  
then  find  the  right  
portlet.
 
 
There  is  a  lot  of  portlet  available  out  of  the  box.  Some  useful  ones  are:
 
 
-­‐

Web  Content  Display  

 
allows  you  to  display  html  content
 
-­‐

Naviguation  

 
shows  the  naviguation
 
-­‐

Site  Map  
(package
 
Content  Management
)  

 
shows  a  site  map
 
-­‐

Iframe  
(package
 
Sample
)  

 
lets  you  put  an  external  web  page  into  the  portlet
 
1.4.

Configure  portlets
 
There  are  always  little  icons  to  enable  you  to  update  content  or  configure  the  portlets  on  the  page.  To  see  them  you  
mus
t  be  logged  as  
Admin
 
and  
Toggle  Edit  Controls
 
must  be…  toggled.  
 
For  Instance,  to  update  content  from  a  
Web  Content  Display
,  click  the  
pen  icon
 
at  the  bottom  of  the  portlet.
 
To  set  the  url  to  display  into  an  
Iframe
 
portlet,  click  the  
Wrench  icon
 
on  the  top
 
right  hand  corner  and  then  click  
Configuration
.
 
To  access  custom  portlet’s  
edit  mode
,  also  click  the  Wrench  icon  then  go  to  
Preferences
.
 
 
 
 
2.

Liferay  General  Configuration
 
2.1.

Main  configuration  file
 
Location  of  
portal
-­‐
ext.properties
:
 
/liferay
-­‐
portal
-­‐
<version>
/t
omcat
-­‐
<version>
/webapps/ROOT/WEB
-­‐
INF/classes/
 
2.2.

Chat  Portlet  

 
Annoying  Ajax  requests
 
Some  portlets  are  installed  when  deploying  the  portal  for  the  first  time  such  as  the  Chat  Portlet.  It  does  regular  Ajax  
requests  and  can  interrupt  useful  Ajax  requests  in  y
our  custom  portlets.  Here  is  a  topic  evoking  the  issue:  
http://www.liferay.com/community/forums/
-­‐
/message_boards/mes
sage/9406200;jsessionid=72C17925026CD7CB35A8BBD96F4AE321.node
-­‐
1
 
 
 
 
3.

Create  a  new  Spring  MVC  Liferay  Portlet  project  
using  Liferay  IDE  Tools  for  Eclipse  and  Liferay  
Plugins  SDK
 
3.1.

Installation
 
All  you  need  to  know  is  here:  
http://www.liferay.com/documentation/liferay
-­‐
portal/6.0/development/
-­‐
/ai/installation
 
3.2.

Create  a  new  Eclipse  Project
 
You  will  be  needing  the  Liferay  IDE  for  E
clipse  and  the  Liferay  Plugins  SDK.
 
 
I  used  the  exact  same  version  
of  Eclipse  as  
shown  in  the  installation
 
help
.  I  actually  had  trouble  at  first  when  I  tried  it  
with  a  slightly  different  version
 
(
I  didn’t  have  access  to  the  

Installed  Plugin
s
 
SDK
s

 
section  of  the  Life
ray  
configuration  in  the  Window
/Preference
s
 
view)
 
 
What  I  used:
 
 
Eclipse Java EE IDE for Web Developers.


Version: Helios Service Release 2

Build id: 20110218
-
0911
 

Liferay IDE v1.2.3v201103310212


Plugin
s

SDK v6.0.5

 
Now  do:
 
 
Run
 
Eclipse  (run!).
 
Do:
 
File>New>Liferay  Project
 
 
Either  give  it  a  funny  name  or  a  relevant  one,  your  call.  “
-­‐
portlet”  will  be  automatically  added  at  the  end  of  the  
name.
 
 
Configuration  should  be  set  to:
 
Liferay  Plugins  SDK:  plugins_SDK
 
Liferay  Portal  Runtime
:  [your  version  of  Liferay,  for  instance:  Liferay  v6.0  CE  (Tomcat  6)]
 
 
Plugin  type:
 
Portlet
 
3.3.

Modify  it
 
to  
work  with  Spring  MVC
 
So  you  just  created  a  new  Liferay  portlet.  This  does  not  include  Spring  MVC  yet.
 
In  your  project  in  docroot/WEB
-­‐
INF/  you  should  
have  the  following  xml  configuration  files:
 
-­‐

Liferay
-­‐
display.xml
 
-­‐

Liferay
-­‐
portal.xml
 
-­‐

Portlet.xml
 
-­‐

Web.xml
 
 
You  will  need  
to  create  
one  more  for  Spring  MVC
.
 
Name  it
 
like  this  
[your
-­‐
portlet
-­‐
name]
-­‐
portlet.xml
 
put  it  at  the  
same  level  as  the  others.
 
 
 
Now
,
 
you  will  need  to  add  some  .jar  files  (I’m  not  certain  
which  of  them  are
 
mandatory.
 
I  didn’t  take  the  time  to  
check…  yet…  but  if  you  read  this  it  probably  means  that  in  the  end  I  didn’t  find  time  to  do  it…  or  I  forgot...  I  should  
probably  highlight  this  to
 
make  sure  I  don’t  forget…)
 
 
1)

Add  
portlet.jar  
in  
docroot/lib
/
 
 
2)

Add  the  following  files  in  
docroot/WEB
-­‐
INF/lib/
:
 
o

org.springframework.asm
-­‐
[version].jar
 
o

org.springframework.beans
-­‐
[version].jar
 
o

org.springframework.context
-­‐
[version].jar
 
o

org.springframework.conte
xt.support
-­‐
[version].jar
 
o

org.springframework.core
-­‐
[version].jar
 
o

org.springframework.expression
-­‐
[version].jar
 
o

org.springframework.web
-­‐
[version].jar
 
o

org.springframework.web.portlet
-­‐
[version].jar
 
o

org.springframework.web.servlet
-­‐
[version].jar
 
o

org.springframework.jdbc
-­‐
[version].jar  
(if  
you  wish  to  use  Spring’s  JDBC  API)
 
o

org.springframework.transaction
-­‐
[version].jar  
(not  sure  if  always  needed)
 
o

standard.jar  
(not  sure  if  needed)
 
 
3)

Next,  double  click  
docroot/WEB
-­‐
INF/liferay
-­‐
plugin
-­‐
package.properties
 
and  add  to  
Portal  Dependency  Jars
:
 
o

jstl
-­‐
api.jar
 
o

jstl
-­‐
impl.jar
 
o

commons
-­‐
dbcp.jar
 
o

commons.pool.jar
 
 
Okay  so  next  let’s  
take  care  of
 
all  the  
xml  
configuration  files.
 
3.4.

How  to  configure  Liferay
-­‐
display.xml
 
This  one  is  used  by  Liferay  to  define  how  it  will  be  
displayed  in  the  list  of  all  apps
.
 
 
 
<?
xml

version
=
"1.0"
?>

<!
DOCTYPE

display

PUBLIC

"
-
//Liferay//DTD Display 6.0.0//EN"

"http://www.liferay.com/dtd/liferay
-
display_6_0_0.dtd"
>


<
display
>


<
category

name
=
"category.[category name]"
>



<
portlet

id
=
"[id of the

portlet defined in Liferay
-
portlet.xml]"

/>


</
category
>

</
display
>

3.5.

How  to  configure  Liferay
-­‐
portlet.xml
 
This  file  is  u
sed  to  
set  some  Liferay
-­‐
related  behavior  of  the  portlet.  
Like  access  information  and  also  CSS  and  JS  
includes
.  Great  help  there:
 
http://content.liferay.com/4.3/doc/devel/liferay_4_portlet_development_guide/multipage/ch02.html
 
 
<?
xml

version
=
"1.0"
?>

<!
DOCTYPE

liferay
-
portlet
-
app

PUBLIC

"
-
//Liferay//DTD Portlet Application 6.0.0//EN"

"http://www.liferay.com/dtd/liferay
-
portlet
-
app_6_0_0.dtd"
>


<
liferay
-
portlet
-
app
>


<
portlet
>



<
portlet
-
name
>
[portlet
-
name]
</
portlet
-
name
>



<
icon
>
/icon.png
</
icon
>

 





<
preferences
-
unique
-
per
-
layout
>
false
</
preferences
-
unique
-
per
-
layout
>



<
preferences
-
owned
-
by
-
group
>
false
</
preferences
-
owned
-
by
-
group
>






<
instanceable
>
true
</
instanceable
>






<
header
-
portlet
-
css
>
/css/extjs/ext
-
all.css
</
header
-
portlet
-
css
>






<
header
-
portlet
-
javascript
>
/js/extjs/ext
-
all.js?js_fast_load=0
</
header
-
portlet
-
javascript
>

<!
--

?js_fast_load=0 disables the minifier for this file
--
>


</
portlet
>


<
role
-
mapper
>



<
role
-
name
>
administrator
</
role
-
name
>



<
role
-
link
>
Administrator
</
role
-
link
>


</
role
-
mapper
>


<
role
-
mapper
>



<
role
-
name
>
guest
</
role
-
name
>



<
role
-
link
>
Guest
</
role
-
link
>


</
role
-
mapper
>


<
role
-
mapper
>



<
role
-
name
>
power
-
user
</
role
-
name
>



<
role
-
link
>
Power User
</
role
-
link
>


</
role
-
mapper
>


<
role
-
mapper
>



<
role
-
name
>
user
</
role
-
name
>



<
role
-
link
>
User
</
role
-
link
>


</
role
-
mapper
>

</
liferay
-
portlet
-
app
>

3.1.

Web.xml
 
Web.xml  
defines  general  settings  for  the  application.  
You  can  define  multiple  portlets  here.  
More
 
information  about  
portlet.xml  and  web.xml  there:
 
http://publib.boulder.ibm.com/infocenter/wpdoc/v510/index.jsp?topic=/com.ibm.wp.zos.doc/wps/wpsptdesc.html
 
 
<?
xml

version
=
"1.0"

encoding
=
"UTF
-
8"
?>

<
web
-
app

xmlns:xsi
=
"http://www.w3.org/2001/XMLSchema
-
instance"




xmlns
=
"http://java.sun.com/xml/ns/javaee"




xmlns:web
=
"http://java.sun.com/xml/ns/javaee/web
-
app_2_5.xsd"




xsi:schemaLocation
=
"http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/w
eb
-
app_2_5.xsd"

id
=
"WebApp_ID"

version
=
"2.5"

>


<
display
-
name
>
[portlet
-
name]
-
portlet
</
display
-
name
>


<
servlet
>



<
servlet
-
name
>
ViewRendererServlet
</
servlet
-
name
>



<
servlet
-
class
>
org.springframework.web.servlet.ViewRendererServlet
</
servlet
-
class
>



<
load
-
on
-
startup
>
1
</
load
-
on
-
startup
>


</
servlet
>


<
servlet
-
mapping
>



<
servlet
-
name
>
ViewRendererServlet
</
servlet
-
name
>



<
url
-
pattern
>
/WEB
-
INF/servlet/view
</
url
-
pattern
>


</
servlet
-
mapping
>

</
web
-
app
>

3.2.

Portlet.xml
 
Por
t
let.xml  
defines  settings  specific  to  the
 
portlet  itself.  For  example,  supported  markups,  resource  bundle,  public  
render  par
a
meters,  etc

 
There  can  be  multiple  portlets  in  single  web  application.  But  each  portlet  must  have  its  own  
context.
 
 
 
<?
xml

version
=
"1.0"
?>


<
portlet
-
app


version
=
"2.0"


xmlns
=
"http://java.sun.com/xml/ns/portlet/portlet
-
app_2_0.xsd"


xmlns:xsi
=
"http://www.w3.org/2001/XMLSchema
-
instance"


xsi:schemaLocation
=
"http://java.sun.com/xml/ns/portlet/portlet
-
app_2_0.xsd
http://java.sun.com/xml/ns/portlet/portlet
-
app_2_0.xsd"

>


<
portlet
>



<
portlet
-
name
>
[portlet
-
name]
</
portlet
-
name
>



<
display
-
name
>
[portlet
-
display
-
name]
</
display
-
name
>



<
portlet
-
class
>
org.springframework.web.portlet.DispatcherPortlet
</
portlet
-
class
>






<
supports
>




<
mime
-
type
>
text/html
</
mime
-
type
>




<
portlet
-
mode
>
view
</
portlet
-
mode
>




<
portlet
-
mode
>
edit
</
portlet
-
mode
>



</
supports
>



<
portlet
-
info
>




<
title
>
ActiveMQ
</
title
>



</
portlet
-
info
>


</
portlet
>

</
portlet
-
app
>

3.3.

Lastly
,  
[
portlet
-­‐
name
]
-­‐
portlet.xml
 
This  one  is  used  by  Spring  to  configure  
everything  that  is  Spring  related.
 
All  java  beans  are  defined  here:  controllers  etc…  except  that  it  is  done  automatically  by  Spring  as  we  enabled  
annotations.  You  might  need  to  define  schedulers  or  DAO  beans  here.
 
 
<?
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:p
=
"http://www.springframework.org/schema/p"


xmlns:context
=
"http://www.springframework.org/schema/context"


xmlns:util
=
"http://www.spring
framework.org/schema/util"


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


http://www.springframework.org/schema/util


http://www.springframework.org/schema/util/spring
-
util
-
3.0.xsd


"
>



<!
--

Auto
-
detect controllers in these packa
ges
--
>


<
context:component
-
scan

base
-
package
=
"web"

/>


<!
--

We're using Annotations
--
>


<
context:annotation
-
config
/>



<!
--

View Resolver
--
>


<
bean

id
=
"viewResolver"

class
=
"org.springframework.web.servlet.view.InternalResourceViewResolver"
>


<
property

name
=
"viewClass"

value
=
"org.springframework.web.servlet.view.JstlView"
/>


<
property

name
=
"prefix"

value
=
"/WEB
-
INF/jsp/"

/>


<
property

name
=
"suffix"

value
=
".jsp"

/>


</
bean
>

</
beans
>

 
3.4.

Make  it  work
 
Add  all  .jsp  files  in  
docroot/WEB
-­‐
INF/jsp/
 
as  specified  in  
[portlet
-­‐
name]
-­‐
portlet.xml
 
by  this  line  :  
<
property

name
=
"prefix"

value
=
"/WEB
-
INF/jsp/"

/>

Or  you  can  edit  that  line  to  put  them  somewhere  else.
 
 
As  specified  in  
[portlet
-­‐
name]
-­‐
portlet.xml  
we  will  be  using  Annotations  and  Spring  MVC  will  
scan  all  classes  in  
package  web  to  find  controllers,  services,  drugs.  More  information  in  the  Spring  MVC  portlets
 
section
.
 
 
To  make  this  example  work,  create  a  new  file  
home.jsp
 
and  put  it  in  the  
docroot/WEB
-­‐
INF/jsp/
.  Write  something  
amusing  in  it.
 
 
All  classes  go  into  
docroot/WEB
-­‐
INF/scr/
.
 
C
reate  a  class  
web.controllers.MainController
 
with  this  inside:
 
 
package

web.controllers;


import

org.springframework.stereotype.Controller;

import

org.springframework.web.bind.annotation.RequestMapping;

import

org
.springframework.web.portlet.bind.annotation.RenderMapping;


@Controller

@RequestMapping
(
"VIEW"
)

public

class

MainController {


@RenderMapping


public

String setModelAndView() {



return

"home"
;


}

}


Open  Ant  window  and  hit  Deploy  (a  server  must  be  
running  on  your  local  machine).
 
Then  go  to
 
http://localhost:8080/
.
 
Logged  as  admin,  create  a  new  page,  click  
Add
 
from  the  
top  toolbar
 
and  find  your  portlet  in  the  category  you  have  
entered  in  
Liferay
-­‐
display.xml
.  Drag
 
and  drop  it  on  the  page.  Then  it  should  work.
 
 
You  might  need  to  
right  click  on  the  server
 
in  the  server  view  and  click  
Add  and  remove…
 
then  move  them  from  
Available
 
to  
Configured
.  I’m  still  not  sure  what  this  does.
 
 
 
4.

Develop  portlets  for  Liferay  using  
Spring  MVC
 
4.1.

Introduction
 
There  are  two  main  ways  to  handl
e  configuration  with  Spring  MVC  :  t
he  old  way,  with  
XML  files
,  and  the  most  recent  
way  with  
annotations
.  I  will  only  talk  about  the  annotations
-­‐
driven  way.
 
 
Multiples  portlets  can  be  defined  in  the  sa
me  Web
 
a
pp
lication
.  But  it  seems  that  each  portlet  
has  to
 
have  its  own  
Spring  MVC  context.  
It  
should
 
possible  to  share  data  between  portlets.  
See:
 
http://publib.boulder.ibm.com/infocenter/wpdoc/v510/index.jsp?topic=/com.ibm.wp.zos.doc/wps/wpsptdesc.html
 
http://www.liferay.com/community/forums/
-­‐
/message_boards/message/5446470
 
4.2.

Useful  links
 
In  some  of  these  links  they  do  not  use  annotations
-­‐
driven  conf  but  are  still  below  because  they  are  still  helpful  for  
some  other  reason.
 
 
http://static.springsource.org/spring/docs/current/spring
-­‐
framework
-­‐
reference/html/mvc.html
 
http://static.springsource.org/spring/docs/2.0.0/reference/portlet.html
 
http://levelup.lishman.com/spring/getting
-­‐
started/index.php
   
(real  good  tutorial)
 
http://books.dzone.com/articles/hello
-­‐
world
-­‐
portlet
-­‐
using
-­‐
Spring
-­‐
3
-­‐
portlet
-­‐
MVC
 
(good  tutorial)
 
http://books.dz
one.com/articles/spring
-­‐
30
-­‐
portlet
-­‐
mvc
-­‐
part
-­‐
2
 
(good  tutorial)
 
http://www.infoq.com/articles/spring
-­‐
2.5
-­‐
ii
-­‐
spring
-­‐
mvc
 
http://www.unicon.ne
t/node/1367
 
http://static.springsource.org/spring/docs/3.0.0.RELEASE/spring
-­‐
framework
-­‐
reference/html/beans.html
#beans
-­‐
annotation
-­‐
config
 
http://weblogs.java.net/blog/seemarich/archive/2007/11/annotation_base.html
 
http://integratingstuff.com/2011/05/29/getting
-­‐
started
-­‐
with
-­‐
portals
-­‐
writing
-­‐
a
-­‐
portlet
-­‐
with
-­‐
spring
-­‐
portlet
-­‐
mvc
-­‐
and
-­‐
deploying
-­‐
it
-­‐
to
-­‐
a
-­‐
portal/
 
http://www.esup
-­‐
portail.org/consortium/espace/Normes_1C/portlet
-­‐
spring/esup
-­‐
portlet
-­‐
spring.html
 
http://www.andypemberton.com/spring/annotation
-­‐
based
-­‐
spring
-­‐
portlet
-­‐
mvc
-­‐
lifecycle/
 
http://www.slideshare.net/johnalewis/annotation
-­‐
based
-­‐
spring
-­‐
portlet
-­‐
mvc
 
http://jonathanhui.com/spring
-­‐
mvc
-­‐
controller
 
http://www.google.com/
 
 
 
4.3.

Spring  MVC  
principle
 
 
Source  :  
http://www.andypemberton.com/spring/annotation
-­‐
based
-­‐
spring
-­‐
portlet
-­‐
mvc
-­‐
lifecycle/
 
 
As  it  we  are  using  the  annotation
-­‐
driven  configurati
on,  classes  will  need  to  be  annotated  in  order  for  Spring  to  use  
them.  In  
[por
t
let
-­‐
name]
-­‐
portlet.xml
,  this  must  be  set:
 
<
context:annotation
-
config
/>
 
 
The  main  types  are:
 
@Controller
 
for  web  controllers.  They  are  used  to  handle  user  requests  and  redirect  to  views.
 
@Service
 
for  web  services.
 
@Repository
 
for  DAO  classes  etc…
 
 
All  these  classes  need  to  be  in  a  certain  package  referred  to  by  this  line  in  
[por
t
let
-­‐
name]
-­‐
portlet.xml
.
 
<
conte
xt:component
-
scan

base
-
package
=
"web"

/>

 
Portlets  can  be  displayed  in  three  modes.  The  normal  mode  called  
view
 
plus  the  
edit
 
and  
help
 
modes.
 
4.4.

Dependency  Injection
 
Dependency  Injection  in  Spring  MVC  can  be  used  to  link  a  Controller  to  a  running  Web  Service.  
When  xml  
configuration  would  have  you  write  some  really  long  configuration  nodes  to  link  JavaBeans,  annotations  make  it  all  a  
lot  easier.
 
 
Let’s  say  that  you  have  a  Server  called  UselessService.
 
Create  a  package  
web.services  
and  create  the  class  
UselessSer
vice
.
 
 
Put  this  inside:
 
 
package

web.services;


import

org.springframework.stereotype.Service;

 

@Service

public

class

UselessService {


public

void

u
selessMethod() {



System.
out
.println(
"Wow! This was useless..."
);


}

}


If  you  need  to  use  the  method  
u
selessMethod()  or  this  service  in  one  of  your  controller,  
just  write  this  inside  the  
controller:
 
 
private

UselessService
uselessService
;



@Autowired

public

void

setUselessService(UselessService uselessService) {


this
.
uselessService

= uselessService;

}


Then  simply  call  the  method  by  doing

uselessService
.
u
selessMethod()
.  Spring  injects  all  dependencies  when  
the  portlet  is  being  deployed  and  you  will  get  a  nasty  Exception  if  it  can’t  do  it  because  you  did  something  wrong  
(tried  to  autowire  a  class  that  doe
sn’t  have  the  
@Service
annotation  etc…).
 
 
@Autowired
does  all  the  work  by  itself  as  long  as  there  is  only  1  instance  of  this  type  of  Service/Repository.  If  there  
is  more  than  one,  you  will  need  to  use  the  annotation  
@Qualifier
.

4.5.

Mapping
 
So  controllers  will  
need  to  be  annotated  according  to  the  mode  they  will  be  used  for.  For  instance,  the  following  
controller  will  be  used  for  the  edit  mode:
 
 
@Controller

@RequestMapping
(
"VIEW"
)

public

class

MainController {


View
 
mode  is  the  main  mode  you  will  be  using.  
Edit
 
mode  can  be  used  to  allow  Admins  to  set  preferences  for  the  
portlet  (there  is  a  part  about  this  somewhere  hidden  in  this  documentation).
 
 
To  direct  a  user  from  one  view  to  and  other,  you  will  use  the  annotation  
@RenderMapping
.  This  allows  you  to  set  
Model
 
parameters  and  the  View  to  show.
 
There  is  another  important  annotation:

@ActionMapping
.  It  is  used  to  perform  certain  actions  (such  as  inserting  
some  data  into  the  database).
 
4.5.1.

RenderMapping
 
In  a
 
view  (a  .jsp  file,  let’s  call  
it  page1.jsp),  when  you  need  to
 
set  a  link  for  the  user  to  reach  another  view  (page2.jsp),  
here  is  what  you  will  enter  in  your  .jsp  file:
 
 
<%@

taglib

prefix
=
"portlet"

uri
=
"http://java.sun.com/portlet"

%>


<
portlet:renderURL

var
=
"showPage2URL"
>


<
portlet:param

name
=
"action"

value
=
"showPage2"

/>

</
portlet:renderURL
>


<
a

href
=
"
${showPage2URL}
"
>
Show me page 2
</
a
>


Then,  in  your  
MainC
ontroller
.java
,  you  will  need  a  method  that  looks  like  this:
 
 
@RenderMapping
(params =
"action=showPage2"
)

public

String showPage2() {


return

"page2"
;

 
}


The  name  of  the  method  can  be  anything  you  want,  be  creative.  The  only  constraint  is  that  the  method  returns  a  
String  that  represents  the  name  of  the  view  (page2  
-­‐
>  page2.jsp).
 

So  now  you’re  thinking:  
“okay  great,  but  how  do  I  tell  Spring
 
MVC  
what  the  mai
n  page  is?  The  page  the  user  
gets  to  
when  he  opens  the  portlet?”
.
 
It’s  easy.  S
omewhere  in  one  of  you  controller,  you  just  need  a  
@RenderMapping
 
with  no  param
eter
.  
Like  this:
 
 
@RenderMapping

public

String setModelAndView() {


return

"page1"
;

}


So  your  
MainController
.java
 
should  look  like  this:
 
 
package

web.controllers;


import

org.springframework.stereotype.Controller;

import

org.springframework.web.bind.annotation.RequestMapping;

import

org.springframework.web.portlet.bind.annotation.RenderMapping;


@C
ontroller

@RequestMapping
(
"VIEW"
)

public

class

MainController {


@RenderMapping


public

String setModelAndView() {



return

"page1"
;


}




@RenderMapping
(params =
"action=showPage2"
)


public

String showPage2() {



return

"page2"
;


}

}

 
And  it  should  work.
 
4.5.2.

ActionMapping
 
The  main  difference  is  that  ActionMapping  methods  return  nothing.
 
In  a  .jsp  file  things  are  a  little  bit  different,  you  do  not  use  
portlet:renderURL
 
anymore  but  
portlet:actionURL
 
instead.
 
 
Let’s  put  this  into  page2.jsp:
 
 
<%@

taglib

prefix
=
"portlet"

uri
=
"http://java.sun.com/portlet"

%>


<
portlet:actionURL

var
=
"doActionURL"
>


<
portlet:param

name
=
"action"

value
=
"doAction"

/>

</
portlet:actionURL
>


<
a

href
=
"
${doActionURL}
"
>
do Something
</
a
>

 
Now,  still  in  the  MainController
.java
,  add  this  method:
 
 
@ActionMapping
(params =
"action=doAction"
)

public

void

doAction() {


System.
out
.println(
"Congratulations, you just did something."
);

}
 
 
 
Test  it.  And  you  must  realize  that  yes,  the  method  was  called  indeed,  but  you  were  sent  back  to  page1.jsp.  I’m  pretty  
sure  this  is  by  design  and  there  is  only  one  way  I  could  find  to  prevent  this.  Add  this  line  to  your  doAction  method:  
response.setRenderParameter(
"action"
,
"showPage2"
);
 
So  basically  you  did  the  action  but  you  still  have  to  tell  Spring  what  RenderMapping  to  call.  
The  method  would  look  
like:
 
 
@ActionMapping
(params =
"action=doAction"
)

public

void

doAction(ActionResponse response) {


System.
out
.println(
"Congratulations, you
just did something."
);


response.setRenderParameter(
"action"
,
"showPage2"
);

}

4.6.

Pass  Model  Data  to  a  view
 
There  are  two  ways  to  proceed.
 
4.6.1.

Using  the  annotation  @ModelAttribute
 
MainController.java
:


@RenderMapping
(params =
"action=showPage2"
)

public

String show
Page2() {


return

"page2"
;

}
 
@ModelAttribute
(
"something"
)

public

String getSomething() {


return

"bleh bleh bleh"
;

}

p
age
2
.jsp:
 
 
<%@

page

isELIgnored
=
"false"

%>


<%@
taglib

prefix
=
"c"

uri
=
"http://java.sun.com/jsp/jstl/core"

%>


<
c:out

value
=
"
${something}
"
/
>

<!
--

this uses
JSP Expression Language
--
>


The  method  
getSomething()
will  be  called  eve
ry  time  the  controller  is  used.
 
 
T
he  annotated  
@ModelAttribute
methods  are  called  
before
 
the  
@ActionMapping
 
or

@RenderMapping
methods.
 
4.6.2.

Using  the  ModelMap  bean
 
MainController.java
:
 
 
@RenderMapping
(params =
"action=showPage2"
)

public

String showPage2(ModelMap model) {


model.addAttribute(
"something"
,
"blah blah blah"
);


return

"page2"
;

}


p
age
2
.jsp:
 
 
<%@

page

isELIgnored
=
"false"

%>


<%@
taglib

prefix
=
"c"

uri
=
"http://java.sun.com/jsp/jstl/core"

%>


<
c:out

value
=
"
${something}
"
/>

<!
--

this uses
JSP Expression Language
--
>


 
In  this  case,  you  can  generate  Model  data  depending  on  which  
RenderMapping
 
method  is  called.
 
4.7.

RequestParam
 
Now  let  us  see  how  to  pass  parameters  to  a  
RenderMapping
 
or  
ActionMapping
 
method  from  the  JSP.
 
 
page1.jsp
:
 
 
<%@

taglib

prefix
=
"portlet"

uri
=
"http://java.sun.com/portlet"

%>


<
portlet:renderURL

var
=
"showPage2URL"
>


<
portlet:param

name
=
"action"

value
=
"showPage2"

/>


<
portlet:param

name
=
"param1"

value
=
"foo"

/>


<
portlet:param

name
=
"param2"

value
=
"bar"

/>

</
portlet:renderURL
>


<
a

href
=
"
${showPage2URL}
"
>
Show me page 2
</
a
>


MainController
.java
:
 
 
@RenderMapping
(params =
"action=showPage2"
)

public

String showPage2(
@RequestParam

String param1,
@RequestParam

String param2) {


System.
out
.println(
"Param1: "

+ param1);


System.
out
.println(
"Param2: "

+ param2);


return

"page2"
;

}

 
Okay  now  let’s  teach  you  how  to  do  forms  with  Spring  MVC.
 
4.8.

Display  a  list  
of  objects  with  actions
 
First
,  
add  this  to  your  project:
 
 
package

domain.things;


public

class

SomeObject {


private

int

id
;


private

String
name
;


private

String
somethingElse
;




public

int

getId() {



return

id
;


}


public

void

setId(
int

id) {



this
.
id

= id;


}


public

String getName() {



return

name
;


}


public

void

setName(String name) {



this
.
name

= name;


}


public

String getSomethingElse() {



return

somethingElse
;


}


public

void

setSomethingElse(String somethingElse) {



this
.
somethingElse

= somethingElse;


}


public

SomeObject() {}



 

public

SomeObject(
int

id, String name, String somethingElse) {



setId(id);



setName(name);



setSomethingElse(somethingElse);


}


public

String toString() {



return

getId() +
"
\
n"

+ getName() +
"
\
n"

+ getSomethingElse();


}

}

 
MainController
.java
:
 
 
package

web.controllers;


import

java.util.LinkedList;

import

java.util.List;


import

org.springframework.stereotype.Controller;

import

org.springframework.ui.ModelMap;

import

org.springframework.web.bind.annotation.RequestMapping;

import

org.springframework.web.bind.annotation.RequestParam;

import

org.springframework.web.portlet.bind.annotation.ActionMapping;

import

org.springframework.web.portlet.bind.annotation.RenderMapping
;


import

domain.things.*;


@Controller

@RequestMapping
(
"VIEW"
)

public

class

MainController {


@RenderMapping


public

String setModelAndView(ModelMap model) {



List<SomeObject> listOfSomeObject =
new

LinkedList<SomeObject>();



listOfSomeObject.add(
new

SomeObject(13,
"Object 13"
,
"
aze
"
));



listOfSomeObject.add(
new

SomeObject(56,
"Object 56"
,
"
aze
"
));



listOfSomeObject.add(
new

SomeObject(41,
"Object 41"
,
"
aze
"
));



listOfSomeObject.add(
new

SomeObject(11,
"Object 11"
,
"
aze
"
));






model.addAttribute(
"listOfSomeObject"
, listOfSomeObject);






return

"page1"
;


}




@ActionMapping
(params =
"action=doSomethingWithSomeObject"
)


public

void

doSomethingWithSomeObject(
@RequestParam

int

someObjectId) {



System.
out
.println(
"SomeObjectId: "

+ someObjectId);


}

}


page1.jsp
:
 
 
<%@

taglib

prefix
=
"c"

uri
=
"http://java.sun.com/jsp/jstl/core"

%>

<%@

taglib

prefix
=
"portlet"

uri
=
"http://java.sun.com/portlet"

%>

<%@

taglib

prefix
=
"spring"

uri
=
"http://www.springframework.org/tags"

%>


<
table
>


<
tr
>



<
td
>
Id
</
td
>



<
td
>
Name
</
td
>



<
td
>
Action
</
td
>


</
tr
>


<
c:forEach

var
=
"someObject"

items
=
"
${listOfSomeObject}
"
>



<
tr
>




<
td
><
c:out

value
=
"
${someObject.id}
"

/></
td
>

<!
--

Automatically calls someObject.getId()
--
>

 



<
td
><
c:out

value
=
"
${someObject.name}
"

/></
td
>

<!
--

Automatically calls someObject.getName()
--
>




<
td
><
a





href
=
"





<
portlet:actionURL
>






<
portlet:param

name
=
"action"

value
=
"doSomethingWithSomeObject"

/>






<
portlet:param

name
=
"someObjectId"

value
=
"
${someObject.id}
"
/>





</
portlet:actionURL
>









"
><
strong
>
Do something
</
strong
></
a
>



</
tr
>


</
c:forEach
>


</
table
>


Now  you  have  a  real  ugly  list  that  can  perform  actions  etc…
 
4.1.

Forms
 
4.1.1.

Very  basic  form
 
page1.jsp
:
 
 
<%@

taglib

prefix
=
"c"

uri
=
"http://java.sun.com/jsp/jstl/core"
%>

<%@

taglib

prefix
=
"portlet"

uri
=
"http://java.sun.com/portlet"

%>

<%@

taglib

prefix
=
"form"

uri
=
"http://www.springframework.org/tags/form"
%>


<!
--

Link
--
>

<
portlet:actionURL

var
=
"doSimpleFormURL"
>


<
portlet:param

name
=
"action"

value
=
"doSimpleForm"

/>

</
portlet:actionURL
>


<
!
--

Form
--
>

<
form

method
=
"POST"

action
=
"
${doSimpleFormURL}
"
>


<
input

name
=
"input1"

id
=
"input1"

value
=
"
<
c:out

value
=
"
${stuff}
"
/>
"

/>


<
input

type
=
"submit"

value
=
"Submit"

/>

</
form
>

 
MainController.java
 
 
package

web.controllers;


import

javax.portlet.ActionRequest;


import

org.springframework.stereotype.Controller;

import

org.springframework.web.bind.annotation.ModelAttribute;

import

org.springframework.web.bind.annotation.RequestMapping;

import

org.springframework.web.bind.annotation.Re
questParam;

import

org.springframework.web.portlet.bind.annotation.ActionMapping;

import

org.springframework.web.portlet.bind.annotation.RenderMapping;


@Controller

@RequestMapping
(
"VIEW"
)

public

class

MainController {


@RenderMapping


public

String setModelAndView() {



return

"page1"
;


}




@ModelAttribute
(
"stuff"
)


public

String getStuff() {



return

"some stuff"
;


}

 



@ActionMapping
(params =
"action=doSimpleForm"
)


public

void

changePreferences(
@RequestParam

String input1, ActionRequest
a
ctionRequest) {



System.
out
.println(input1);


}

}

4.1.2.

More  advanced  form
 
Okay  now  sometimes  you  may  want  to  build  more  complex  forms.  Maybe  you  have  an  object,  and  you  want  to  
populate  it  with  a  form.  So  here’s  how  I’d  do  it:
 
We’ll  be  using  again  
domain.things.SomeObject.java
 
described  a  few  pages  up.
 
 
MainController.java:
 
 
package

web.controllers;


import

org.springframework.beans.propertyeditors.StringTrimmerEditor;

import

org.springframework.stereotype.Controller;

import

org.springframework.web.bind.WebDataBinder;

import

org.springframework.web.bind.annotation.InitBinder;

import

org.springframework.web.bind.annotation.ModelAttribute;

import

org.springframework.web.bind.annotation.RequestMapping;

import

org.springframework
.web.portlet.bind.annotation.ActionMapping;

import

org.springframework.web.portlet.bind.annotation.RenderMapping;


import

domain.things.*;


@Controller

@RequestMapping
(
"VIEW"
)

public

class

MainController {


@RenderMapping


public

String showForm() {



return

"page1"
;


}




@InitBinder
(
"someObject"
)


public

void

initBinder(WebDataBinder dataBinder) {



dataBinder.setDisallowedFields(
new

String[] {
"somethingElse"
});
// to make
sure that we won't try to set this value in the form



dataBinder.setRequiredFi
elds(
new

String[] {
"id"
,
"name"
});



dataBinder.registerCustomEditor(String.
class
,
new

StringTrimmerEditor(
false
));
// removes leading and trailing whitespace from a String.


}



@ModelAttribute
(
"someObject"
)


public

SomeObject getSomeObject() {



return

new

SomeObject(666,
"I'm the devil"
,
"What?"
);


}




@ActionMapping
(params =
"action=doFormAction"
)


public

void

doFormAction(
@ModelAttribute

SomeObject someObject) {



System.
out
.println(someObject.toString());


}

}


page1.jsp
 
 
<%@

taglib

prefix
=
"c"

uri
=
"http://java.sun.com/jsp/jstl/core"

%>

<%@

taglib

prefix
=
"portlet"

uri
=
"http://java.sun.com/portlet"

%>

<%@

taglib

prefix
=
"form"

uri
=
"http://www.springframework.org/tags/form"
%>


 
<!
--

Link
--
>

<
portlet:actionURL

var
=
"doFormActionURL"
>


<
portlet:param

name
=
"action"

value
=
"doFormAction"

/>

</
portlet:actionURL
>


<!
--

Form
--
>

<
form:form

name
=
"form"

modelAttribute
=
"someObject"

method
=
"post"

action
=
"
${doFormActionURL}
"
>


<
table
>



<
tr
>




<
td
><
form:input

path
=
"id"

/></
td
>

</tr>



<tr>




<
td
><
form:input

path
=
"name"

/></
td
>



</
tr
>


</
table
>


<
input

type
=
"submit"

value
=
"Just do it"

/>

</
form:form
>
 
4.1.3.

CustomValidators
 
What  we  did  before  is  great  but  when  the  inputs  are  left  empty,  it  raises  an  error.  Same  thing  when  you  enter  
something  other  than  a  number  into  the  id  input.  That’s  were  
custom  validators
 
come  in.
 
You  will  need  a  .properties  file  with  some  error  codes.  They’re  described  later  in  this  doc,  basically,  you  need  to  add  
this  to  the  
[portlet
-­‐
name]
-­‐
portlet.xml
 
file:
 
<
bean

id
=
"messageSource"

class
=
"org.springframework.context.support.ReloadableResourceBundl
eMessageSource"

p:basename
=
"/WEB
-
INF/
messages
"

/>

 
Then  create  the  file  
messages.properties
 
in  
docroot/WEB
-­‐
INF/
 
and  put  this  inside:
 
 
validation.error.isEmpty=
The

field

is

empty,

how

do

you

expect

the

form

to

validate?

validation.error.formatIsntRight=
Wrong

format!

Think

before

you s
ubmit!

 
Your  error  messages  have  to  be  
really
 
mean  and  condescending.
 
 
Create  
the  class  
SomeObjectValidator
.java:
 
 
package

web.controllers;


import

org.springframework.stereotype.Component;

import

org.springframework.validation.Errors;

import

org.springframework.validation.ValidationUtils;

import

org.springframework.validation.Validator;


import

domain.things.*;


@Component

public

class

SomeObjectValidator
implements

Validator {


public

boolean

sup
ports(Class<?> klass) {



return

SomeObject.
class
.isAssignableFrom(klass);


}



public

void

validate(Object target, Errors errors) {



SomeObject someObject = (SomeObject)target;



ValidationUtils.
rejectIfEmptyOrWhitespace
(errors,
"id"
,
"validation.error.isEmpty"
);



ValidationUtils.
rejectIfEmptyOrWhitespace
(errors,
"name"
,
"validation.error.isEmpty"
);






int

id = someObject.getId();



int

idLength = Integer.
toString
(id).length();

 


if

(idLength > 50 || idLength < 1) {




errors.rejectV
alue(
"id"
,
"validation.error.formatIsntRight"
);



}






String name = someObject.getName();



if

(name.length() > 100 || name.length() < 2) {




errors.rejectValue(
"name"
,
"validation.error.formatIsntRight"
);



}


}

}
 
 
MainController.java:
 
 
package

web.controllers;


import

javax.portlet.ActionResponse;


import

org.springframework.beans.factory.annotation.Autowired;

import

org.springframework.beans.propertyeditors.StringTrimmerEditor;

import

org.springframework.stereotype.Controller;

import

org.springframework.validation.BindingResult;

import

org.springframework.web.bind.WebDataBinder;

import

org.springframework.web.bind.annotation.InitBinder;

import

org.springframework.web.bind.annotation.ModelAttribute;

import

org.springframework.web.bind.
annotation.RequestMapping;

import

org.springframework.web.bind.annotation.SessionAttributes;

import

org.springframework.web.bind.support.SessionStatus;

import

org.springframework.web.portlet.bind.annotation.ActionMapping;

import

org.springframework.web.portlet.bind.annotation.RenderMapping;


import

domain.things.*;


@Controller

@RequestMapping
(
"VIEW"
)

@SessionAttributes
(
"machinesGroup"
)
// keeps the object in session memory
between

postbacks

public

class

MainController {


@RenderMapping


public

String showForm() {



return

"page1"
;


}




@Autowired


private

SomeObjectValidator
someObjectValidator
;




@InitBinder
(
"someObject"
)


public

void

initBinder(WebDataBinder dataBinder) {



dataBinder.setDisallowedFields(
new

String[] {
"somethingElse"
});
// to make
sure that we won't try to set this value in the form



dataBinder.setRequiredFields(
new

String[] {
"id"
,
"name"
});



dataBinder.registerCustomEditor(String.
class
,
new

StringTrimmerEditor(
false
));
// removes leading and trailing

whitespace from a String.


}



@ModelAttribute
(
"someObject"
)


public

SomeObject getSomeObject() {



return

new

SomeObject(666,
"I'm the devil"
,
"What?"
);


}




@ActionMapping
(params =
"action=doFormAction"
)


public

void

doFormAction(
@ModelAttribute

SomeObject someObject, BindingResult
bindingResult, ActionResponse response, SessionStatus sessionStatus) {



someObjectValidator
.validate(someObject, bindingResult);



if

(!bindingResult.hasErrors()) {




System.
out
.println(someObject.toString());

 



//
sets the session status as complete to cleanup the model
attributes stored using @SessionAttributes




sessionStatus.setComplete();
//
With
Spring 3.1.0
, it doesn’t seem to
work with ActionMapping (it does with RenderMapping). Is it a bug?



}


}

}

 
page1.
jsp:
 
 
<%@

taglib

prefix
=
"c"

uri
=
"http://java.sun.com/jsp/jstl/core"

%>

<%@

taglib

prefix
=
"portlet"

uri
=
"http://java.sun.com/portlet"

%>

<%@

taglib

prefix
=
"form"

uri
=
"http://www.springframework.org/tags/form"
%>


<!
--

Link
--
>

<
portlet:actionURL

var
=
"doFormActionURL"
>


<
portlet:param

name
=
"action"

value
=
"doFormAction"

/>

</
portlet:actionURL
>


<!
--

Form
--
>

<
form:form

name
=
"form"

modelAttribute
=
"someObject"

method
=
"post"

action
=
"
${doFormActionURL}
"
>


<
table
>



<
tr
>




<
td
><
form:input

path
=
"id"

/></
td
>




<
td
><
form:errors

path
=
"id"

/></
td
>



</
tr
>



<
tr
>




<
td
><
form:input

path
=
"name"

/></
td
>




<
td
><
form:errors

path
=
"name"

/></
td
>



</
tr
>


</
table
>


<
input

type
=
"submit"

value
=
"Just do it"

/>

</
form:form
>
 
4.2.

Do  Ajax
 
It  is  possible  to  do  ajax  calls,  this  works  pretty  much  like  the  other  Mapping  actions.  This  time  it  uses  the  annotation  
@ResourceMapping
.
 
The  main  difference  between  
@ResourceMapping
 
and  
@RenderMapping
 
is  that
 
a  
RenderMapping  HTTP  requests  returns  the  whole  HTML  for  the  portal  page,  with  all  other  portlets,  when  the  
ResourceMapping  only  returns  
what  you  give  it.

 
page1.jsp
:
 
 
<%@

taglib

prefix
=
"portlet"

uri
=
"http://java.sun.com/portlet"

%>

 
<
portlet:resourceURL

var
=
"doAjaxURL"

id
=
"doAjax"

escapeXml
=
"false"

/>

<
script

type
=
"text/javascript"
>


<%@

include

file
=
"/js/getCharts.js"

%>

</
script
>

 
essai.js  (using  Ext  JS
,  requires  
to  include  some  .js  files  in  the  page
,  but  it’s  just  a  sample
):
 
 
Ext.Ajax.request({


url:
"${
doAjaxURL
}"
,

params
: {



param1:
"H
i
"


},

success:
function
(response) {




alert(response.responseText);


}

});

 

MainController
.java
:
 
 
@ResourceMapping
(value=
"
doAjax
"
)

public

void

doAjax(ResourceRequest request, ResourceResponse response,
@RequestParam

String param1){


response.setContentType(
"application/x
-
json"
);


response.getWriter().print(
"
Hi back
!"
);

}


One  thing  you  should  know  is  
that  when  you  have  an  application  that  does  Ajax  requests  while  
y
ou  are  hot  
redeploying  the  portlet  that  
contains  the  application,  you  may  get  errors  in  the  tomcat  console.  I  haven’t  found  a  
way  to  prevent  this  yet.  You  can  either  restart  the  server  or  close  all  web  browsers  that  do  the  Ajax  calls.
 
 
 
 
5.

Make  
Portlets,  
tips
 
5.1.

Init  and  destroy  methods  of  a  
component
 
Init  Method:
 
Create  a  method  in  the  Service
 
and  annotate  it  with
:
 
@PostConstruct
 
 
Destroy  Method:
 
Create  a  method  in  t
he  Service  and  annotate  it  with
:
 
@PreDestroy

5.2.

Get  Context  Path
 
-­‐
 
client
 
side  
technology
.
 
Write  the  context
-­‐
path  in  a  JSP  file:
 
<
c:out

value
=
"
${pageContext.request.contextPath}
"

/>


5.3.

access  renderRequest,  renderResponse  in  jsp
 
Add  this:

<
portlet:defineObjects
/>


Example:  Test  portlet  mode
 
:
 
<
c:choose
>


<
c:when

test
=
"
<%=
renderRequest.getPortletMode().equals(javax.portlet.PortletMode.VIEW)
%>
"
>



aze


</
c:when
>

</
c:choose
>
 
5.4.

Get  
P
ortlet  
C
ontext
 
and  Context  
R
eal  Path
 

 
server  side
 
In  your  controller  class,  just  add  this:
 


private

PortletContext
portletContext
;



@Autowired

public

void

setPortletContext(PortletContext portletContext) {


this
.
portletContext

= portletContext;

}


Then  use:
 
portletContext
.getRealPath(
"/"
)
 
5.5.

Access  static  resources
 
docroot
 
-­‐

i
mages
 
o

image.jpg
 
-­‐

resources
 
-­‐


 
-­‐

WEB
-­‐
INF
 
o

jsp
 
o


 
 
If  you  need  to  access  static  content  in  the  “resources”  folder
 
(for  instance  image.jpg)
,  
put
 
in  
[
portlet
-­‐
name
]
-­‐
por
t
let.xml
 
:
 
<
mvc:resources

mapping
=
"/
images
/**"

location
=
"/
images
/"

/>
 
 
 
Then  access  it  using:
 
<
img

src
=
"
<
c:url

value
=
"/images/image.jpg"

/>
"

/>

5.6.

messages
.properties  files
 
You  can  create  .properties  files  to  handle  multiple  languages  etc…
 
They  look  like  this:
 
 
global.actions.Edit=
Edit

global.actions.Delete=
Delete

global.actions.Remove=
Remove

global.actions.Action=
Action

global.actions.Add=
Add

global.actions.Ok=
Ok


To  be  able  to  use  them,  you  need  to  add  this  somewhere  in  the  
[portlet
-­‐
name]
-­‐
portlet.xml
 
file:
 
 
<!
--

Access resource bundles with the specified basename
--
>

<
bean

id
=
"messageSource"

class
=
"org.springframework.context.support.ReloadableResourceBundleMessageSource"

p:basename
=
"/WEB
-
INF/[File name without the
.properties extension]"

/>

 
Then  in  a  JSP  file,  do  this:
 
 
<%@

taglib

prefix
=
"spring"

uri
=
"http://www.springframework.org/tags"

%>

<
spring:message

code
=
"
global.action.Edit
"
/>
 
5.7.

Edit  Mode
 
and  Preferences
 
5.7.1.

What  preferences  are
 
Preferences  are  data  
that  can  be  
stored  for  a
 
portlet
 
without  needing  a  database
.  You  can  use  it  to  
make  a  portlet  
configurable.
 
5.7.2.

Help  
with
 
preferences
 
http://blog.asolutions.com/2010/05/user
-­‐
preferences
-­‐
in
-­‐
liferay/
 
5.7.3.

Enable  edit  mode
 
and  configure  preferences
 
Add  
<
portlet
-
mode
>
edit
</
portlet
-
mode
>
 
to  portlet.xml  in  
<
supports
>

In  Liferay
-­‐
portlet.xml  set  
<
instanceable
>
true
</
instanceable
>
 
(can  have  more  than  o
ne  instance  of  this  
portlet  in  one  page).
 
Advised  configuration:
   
owned
-­‐
by
-­‐
group=true,  unique
-­‐
per
-­‐
layout=true:  
preferences
 
of  a  portlet
 
will  be  
shared  
by
 
all
 
users  but  different  for  each  instance
 
of  the  portlet
.
 
5.7.4.

Access  edit  mode  in  Liferay
 
You  must  be  logged  as  admin.  Click  the  
Wrench  icon
 
and  go  to  
Preferences
.
 
5.7.5.

Portlet  Preferences
 
http://blog.asolutions.com/2010/05/user
-­‐
preferences
-­‐
in
-­‐
liferay/
 
 
5.8.

Minifier  

 
lots  of
 
.js  files  in  tomcat/temp/minifier/…
 
Liferay  minifies  css  and  javascript  files  and  stores  them  in  liferay
-­‐
portal/tomcat/temp
 
To  disable  it,  add  this  in  the  portal
-­‐
ext.properties:
 
com.liferay.portal.servlet.filters.minifier.MinifierFilter=false
 
com.liferay.
portal.servlet.filters.strip.StripFilter=false
 
javascript.fast.load=false
 
 
The  above  may  cause  inconveniences  such  as  the  javascript  of  the  Liferay  components  not  working  anymore…  In  this  
case,  the  best  you  can  do  is  to  add  
?js_fast_load=0
 
to  the  link  to  t
he  
.js
 
file
s
 
in  
liferay
-­‐
portlet.xml
:
 
<
header
-
portlet
-
javascript
>
/js/extjs/ext
-
all.js?js_fast_load=0
</
header
-
portlet
-
javascript
>



 
6.

HSQL  Database
 
6.1.

Exploring  Liferay’s  HSQL  Database
 
The  server  
should  be  off.
 
Use  the  default  HSQLDB  Explorer:
 
Go  to  directory  where  hsql.jar  is  
Liferay
-­‐
portal
-­‐
<version>
\
tomcat
-­‐
<version>
\
lib
\
ext
\
 
java  
-­‐
cp  hsql.jar  org.hsqldb.util.DatabaseManager
 
 
Driver:
   
<path  to  Liferay
-­‐
portal>
\
tomcat
-­‐
<version>
\
lib
\
ext
\
hsql.jar
 
Type:
 
In  memory
 
URL:
 
jdbc:hsqldb:file:
<path  to  
Liferay
-­‐
portal
>
\
tomcat
-­‐
<version>
\
data
\
hsql
\
lportal  (ex:  
jdbc:hsqldb:file:
\
Progra~1
\
Liferay
\
liferay
-­‐
portal
-­‐
6.0.6
\
data
\
hsql
\
sbc
\
sbcdb)
 
Username:
 
sa
 
Password:
 
<blank>
 
 
lportal
 
represents  the  name  of  the  database.  You  will  know  if  it  is  the  right  folder  if  the
re  is  lportal.script  and  
lportal.properties  in  the  folder  (data
\
hsql
\
).  It  may  move  after  Liferay  upgrades.
 
 
 
Tables  are  under  PUBLIC/TABLE    
 
 
You  may  have  to  set:  
hsqldb.lock_file=false
 
in  file:  <path  to  Liferay
-­‐
portal
>
\
data
\
hsql
\
lportal
\
lportal.propertie
s
 
You  may  have  to  delete  the  .lck  file  in  <path  to  
Liferay
-­‐
portal
>
\
data
\
hsql
\
lportal
\
 
 
6.2.

Create  
a  
new  HSQL  Database
 
Do  pretty  much  exactly  like  the  previous  step  but  instead  of  
lportal  
put  the  name  of  your  database
 
 
Usual  HSQL  tables
 
creation  commands
:
 
 
CREATE  TABLE  groups  (
 
   
id  INTEGER  IDENTITY,
 
   
name  VARCHAR(128)  NOT  NULL,
 
)
 
 
CREATE  TABLE  machines  (
 
   
id  IDENTITY,
 
   
ip  VARCHAR(64)  NOT  NULL,
 
   
name  VARCHAR(128)  NOT  NULL
 
)
 
 
CREATE  TABLE  group_machine  (
 
   
group_id  INTEGER  NOT  NULL,
 
   
machine_id  INTEGER  N
OT  NULL,
 
   
FOREIGN  KEY  (group_id)  REFERENCES  groups(id)  ON  DELETE  CASCADE  ON  UPDATE  CASCADE,
 
   
FOREIGN  KEY  (machine_id)  REFERENCES  machines(id)  ON  DELETE  CASCADE  ON  UPDATE  CASCADE
 
)
 
 
IDENTITY  
takes  care  of
 
the  auto
 
i
ncrement.
 
 
6.3.

Launch  a  HSQL  Server
 
Requires  
both  server.bat  and  server.properties  files
 
 
server.bat:
 
java  
-­‐
cp  <path  to  hsql.jar>  org.hsqldb.Server  
-­‐
database.0  file:<name  of  file  .script  without  the  .script>  
-­‐
dbname.0  <alias  of  the  database>
 
 
server.properties:
 
server.port=<server  port>
 
 
Execute  
server.bat  to  launch  the  server
 
6.4.

Connect  to  a  HSQL  database  from  a  Spring  MVC  application
 
Requires  to  add  
hsqldb.jar
 
into  /WEB
-­‐
INF/lib/
 
 
In  Spring  MVC
 
Context  configuration  XML  file
:
 
 
<
bean

id
=
"dataSource"

class
=
"org.springframework.jdbc.datasource.DriverManagerDataSource"
>


<
property

name
=
"driverClassName"
><
value
>
org.hsqldb.jdbcDriver
</
value
></
property
>


<
property

name
=
"url"
>


<
value
>
jdbc:hsqldb:hsql://localhost:
<server port>
/
<alias of the
database>
</
value
>


</
property
>


<
property

name
=
"username"
><
value
>
sa
</
value
></
property
>


<
property

name
=
"password"
><
value
></
value
></
property
>

</
bean
>



 
7.

Use  Ext  JS  in  a  portlet
 
7.1.

Introduction
 
Ext  Js  is  a  javascript  framework
.
 
See  
http://sencha.com
 
for  more  information.
 
7.2.

Installation
 
Download  the  latest  version  from  sen
c
ha.com.  The  .zip  file  downloaded  will  contain  lots  of  files  including  examples  
etc…
 
The  only  files  you  will  really  need  are:
 


ext
-­‐
all.js  or  ext
-­‐
all
-­‐
debug.js
 


ext
-­‐
all.css
 
 
Then  you  might  need  some  images  contained  in  the  “resources”  directory  depending  on  the  components  you’ll  be  
using.
 
Getting  started  guide:
 
http://docs.sencha.com/ext
-­‐
js/4
-­‐
0/#/guide/getting_started
 
7.3.

Use  Ext  JS  into  a  portlet
 
Here’s  a  good  way  to  do  things.  Add  these  files  into  your  project:
 


docroot/js/extjs/ext
-­‐
all.js
 


docroot/css/extjs/ext
-­‐
all.css
 


docroot/images/…  for  some  images,  icons  f
or  grids  etc…
 


docroot/resources/themes/images/default/…  for  theme  images
 
 
Then,  in  
liferay
-­‐
portlet.xml
,  you  should  have  this:
 
<
portlet
>


<
header
-
portlet
-
css
>
/css/extjs/ext
-
all.css
</
header
-
portlet
-
css
>




<
header
-
portlet
-
javascript
>
/js/extjs/ext
-
all.js?js_fast_load=0
</
header
-
portlet
-
javascript
>

</
portlet
>

 
This  add
s
 
the  
.
css  and  
.
js  files  in  the  header  of  the  page  so  you  can  use  them  in  your  portlet  views.  
This  can  create  css  
conflics  between  ext
-­‐
all.css  and  Liferay’s  css.  I  didn’t  f
ind  a  way  to  resolve  these  yet.
 
 
This  is  how  you  add  Ext  JS  to  a  portlet.  
The  addition  of  
?js_fast_load=0
is  to  prevent  Liferay  from  minifing  the  .js  
file.  
There  is  a  part  about  this  in  the  
Liferay  General  Configuration
 
part.
 
7.4.

Architecture  of  an  Ext  Js  
application
 
Here’s  what  a  .js  file  that  uses  Ext  JS  should  look  like:
 
/* Ext.require allows to asynchronously load graphical components (such as panel,
charts etc...). When you need such components (which may not always be the case) it is
required to list
them in here */

Ext.require([


'Ext.panel.*'
,


'Ext.chart.*'
,




'Ext.data.*'
,


'Ext.grid.*'
,


'Ext.util.*'
,

 

...
/* add other components you might need */

]);

Ext.onReady(
function

() {


/* this is where all your code should be (of course functions can be
outside, but
call them from here */

});

7.5.

Change  the  content  of  a  dom  element
 
<
div

id
=
"aze"
></
div
>


<
script

type
=
"text/javascript"
>

Ext.onReady(
function

() {


Ext.get(
"aze"
).dom.innerHTML =
"blah"
;

});

<
/
script
>

7.6.

Important  thing  to  know  about  javascript  
objects
 
When  using  Ext  JS  you  will  find  lots  of  configuration  array  like  this:
 
 
(Do  not
 
put  a  comma  whe
re  
it  says
:

NO COMMA
)
 
 
Ext.create(
'Ext.grid.Panel'
, {


store: store
,


cls:
"css_centered"
,


columns: [


{


text :
'ID'
,


flex : 1
,


resizable:
false
,


sortable :
false
,


draggable:
false
,


hideable :
false
,


dataIndex:
'ID'

NO COMMA


}
,



{


text :
'VALUE'
,


width : 100
,


resizable:
false
,


sortable :
false
,


draggable:
false
,


hideable :
false
,


dataIndex:
'VALUE'

NO
COMMA


}
NO COMMA


]
,


autoHeight:
true
,


width: 400
,


title:
'Top 10 Apps'
,


renderTo:
'div_top10Grid'
,


viewConfig: {


stripeRows:
true

NO COMMA


}
NO COMMA

});

 
Although  Firefox  and  
Chrome  don’t  mind  the  extra  comma,  IE  tends  to  not  like  it  and  not  display  a  single  javascript  
element  in  the  page  if  there  is  a  single  extra  comma.  Then  it’s  really  complicated  to  debug.
 
Be  careful,  it’s  really  easy  to  remove  a  configuration  line  and  forg
et  to  remove  the  previous  comma  if  that  line  was  at  
an  end.
 
 
7.7.

What’s  a  
Ext.
data.
store?
 
This  is  what  Ext  JS  uses  to  store  
d
ata  that  can  be  used  to  display  in  charts  or  grids…
 
These  components  are  bound  to  
a  store,  updating  a  component’s  store  will  automatical
ly  update  its  content.
 
Y
ou  can  load  data  directly  from  inside  t
he  definition  of  your  store,  or  pass  data  to  it.
 
 
Here,  we  define  a  model  for  the  data  contained  into  the  store,  and  then  we  declare  the  store  with  a  pro
xy  object  to  
get  Ajax  data:
 
 
Ext.define(
'User'
, {


extend:
'Ext.data.Model'
,


fields: [


{name:
'firstName'
, type:
'string'
},


{name:
'lastName'
, type:
'string'
},


{name:
'age'
, type:
'int'
},


{name:
'eyeColor'
, type:
'string'
}


]

});


var

myStore =
new

Ext.data.Store({


model:
'User'
,


proxy: {


type:
'ajax'
,


url :
'/users.json'
,


reader: {


type:
'json'
,


root:
'users'


}


},


autoLoad:
true

});


Here  is  a  different  way  to  do  things:
 
 
va
r

data = [{data:
'aze'
}, {data:
'azeazeaze'
}];
 
var

store = Ext.create(
'Ext.data.JsonStore'
, {

fields: [
'data'
],

data: storeData

});


Then  you  can  update  the  data  array  and  apply  the  modifications  to  the  store  like  this:
 
 
store.loadData(data,
false
);


Set  the
 
second  parameter  to  true  to  append  data  to  the  store.
 
 
I  prefer  the  second  way  as  it  allows  you  more  easily  to  load  Ajax  data  into  an  array  and  then  insert  the  new  data  
into  the  store.
 
7.8.

Ajax  Requests
 
Here’s  how  you  do  a  basic  Ajax  request:
 
 
Ext.Ajax.reques
t({



url:
"url"
,



timeout: 1000,
// timeout of Ajax Request



autoAbort:
false
,
// new request aborts previous requests or not



success:
function
(response) {
// called on success

 



var

text = response.responseText;




var

object

= Ext.decode(text);



},



failure:
function
(
result, request
) {
// called on failure



alert(
"
Ajax request Failed<br />status code: "

+ result.status +
"<br
/>status text: "

+ result.statusText +
"<br />response text: "

+ result.responseText)



}


});


It’s  very  important  to  implement  this  som
ewhere  to  catch  ajax  exceptions
:
 
 
Ext.Ajax.on(
'requestexception'
,
function
(){

});
 
7.9.

JSON
 
JSON  stands  for  JavaScript  Object  Notation.
 
It’s  an  efficient  way  to  pass  data  during  Ajax  requests.
 
 
Here’s  a  basic  JSON
 
object:
 
{“id”:12,  “name”:”jean  Charles”}
 
 
Here’s  an  array  of  
3  
JSON  objects:
 
[{“id”:12,  “name”:”Jean  Charles”},  {“id”:1
1
,  “name”:”Jean  Pierre”},  {“id”:1
0
,  “name”:”Jean  Valjean”}]
 
 
Ext  js  can  turn  JSON  string  into  actual  JSON  using  
the  function  Ext.decode
:
 
 
var

array =
new

Array();

array = Ext.decode(
'[{"id":12, "name":"Jean Charles"}, {"id":11, "name":"Jean Pierre"},
{"id":10, "name":"Jean Valjean"}]'
);

var

object0 = array[0];

object0.id;

object0.name;