搭建开发环境
安装 jdk1.4.2,jikes1.22,ant1.6.5
以安装在c盘为例
设置环境变量:
ANT_HOME =C:\apache-ant-1.6.5
JAVA_HOME =C:\jdk1.5
JIKES_HOME=C:\jikes1.22
设置path变量,增加下面信息
%ANT_HOME%\bin;%JAVA_HOME%\bin;%JIKES_HOME%\bin;
部分情况,classpath变量会干扰环境,可以删除。但我机器上没删除classpath都可以正常运作。
设置完环境变量后,最好重新启动机器,保证设置生效。
安装 Myeclipse并建立portal工程
准备好myecipse软件、iferay-portal-src-4.1.0.zip
(1)安装myeclipse。
(2)在e盘建立E:\cmproject目录,将liferay-portal-src-4.1.0.zip解压到e:\cmproject\portal目录下,
(3)进入myeclipse,设置file-->switchworkspace 输入E:\cmproject,ok确认
(4)File -->New-->project-->java project 输入项目名称为portal,其他默认,finish结束
如果一切顺利,则在myeclipse左侧边Navigator上看到portal的整个目录结构
建立ext工程(扩展环境)
(1)在myeclipse下,切换到resource视图模式,展开portal工程目录,我们可看到一个release.properties文件,
实际上我们要建一个它的扩展配置文件,
文件名为release.${username}.properties。 ${username}是计算机当前用户名,比如administrator,apple等等.
在计算机开始菜单运行cmd出来的
c:\document and setting\username>。
为什么非得计算机当前用户名,因为portal用了ant作deploy,里面有个xml配置文件使用了系统环境变量。懒得
去修改配置文件,就照它要求做。
我文件名是release.avidis.properties,文件内容只一行:
lp.ext.dir=e:/cmproject/ext
即扩展工程放置路径。
(2)打开myeclipse里面ant视图(window--> show view --> ant) , 在ant视图中,点击添加,选择e:/cmproject/portal
目录下build.xml
顺序执行clean ,start ,build-ext 成功的话,在e:/cmproject/ext目录下产生一系列的文件和目录。
有时候在执行过程中会失败,报错。主要是portal工程本身没有compile完整。将portal重新build
(project--build automatily)选择上,注意,
让build完成后,再执行clean ,start ,build-ext完成标志是myeclipse 右下角进度条完成100%。
(3)将 liferay-portal-tomcat-jdk5-4.1.0.zip解压到 e:/cmproject/ext/server/tomcat下,在e:/cmproject/ext
目录下我们可以看到app.server.properties文件,
同样我们也要建立一个扩展配置文件 app.server.${username}.properties,文件内容两行:
lp.ext.dir=e:/cmproject/ext
app.server.type=tomcat
(4) 同样建立一个java project。工程名为ext.在myeclipse的Navigator里面可以看到ext工程的目录结构。
配置ext工程tomcat服务器设置
(1) 打开 window --> preference -->myeclipse--> application servers 将其他应用服务器disabble掉,
找到tomcat5,将tomcat home diretory 指向D:\cmproject\ext\servers\tomcat,展开tomcat5,jdk选择我们配置好的jdk1.5
Jdk选项下面 optional jave vm argument输入如下内容:
-Xms256m
-Xmx512m
-Djava.security.auth.login.config=d:/cmproject/ext/servers/tomcat/conf/jaas.config
(2) 将E:\cmproject\ext\servers\tomcat\conf\Catalina\localhost目录下的ROOT.xml文件内容修改为:
<Context path="" docBase="ROOT" debug="0" reloadable="true"
crossContext="true">
<Resource name="jdbc/LiferayPool" auth="Container"
type="javax.sql.DataSource" maxActive="100" maxIdle="30"
maxWait="10000" username="liferay" password="liferay"
driverClassName="com.mysql.jdbc.Driver"
url="jdbc:mysql://192.168.1.101/lportal">
</Resource>
<Resource name="mail/MailSession" auth="Container"
type="javax.mail.Session" mail.transport.protocol="smtp"
mail.smtp.host="localhost">
<Realm className="org.apache.catalina.realm.JAASRealm"
appName="PortalRealm"
userClassNames="com.liferay.portal.security.jaas.PortalPrincipal"
roleClassNames="com.liferay.portal.security.jaas.PortalRole"
debug="99" useContextClassLoader="false">
</Context>
建立ext工程数据库
(1) 在服务器上192.168.1.101安装建mysql数据库服务。
(2) 在192.168.1.101数据库上执行了E:\cmproject\ext\sql\create下的create-mysql.sql
(3)在mysql数据库上建立用户名为liferay,password =liferay,并将databse为lportal的所有权限授予liferay。
(lportal是create-mysql脚本自动建立的)
(4) 解压mysql-connector-java-3.1.12.zip,
将mysql-connector-java-3.1.12-bin.jar
拷贝到e:\cmproject\ext\servers\tomcat\common\lib下。使mysql的jdbc启动程序正常可用。
以上所有步骤顺利完成后,启动myeclipse 里面tomcat服务,启动正常的话,在浏览器里输入http://localhost:8080
可以看到portal系统了。
portlet工程开发简单说明
我们看到无论是portal和ext工程,目录都很繁杂,其实我们只要关注2个目录就够了。portal里面的portal-ejb
和portal-web。Portal-ejb是portal工程已经实现的所有portlet的java代码和部分资源文件.portal-web目录是放置
网页文件和portal的配置文件。
ext工程对应目录是ext-ejb,和ext-web。portal-ejb是放置我们自己开发的portlet的java代码。ext-web是自己开
发portlet对应的网页文件和配置文件。
下面我们来新建一个自己portlet。
这里我们采用portal里面代码规范生成机制。对于持久化层和服务层的类都可以自动产生。我们的portlet功能很
简单就是从数据库里面一个表中获取数据,并在页面上显示。
建立业务数据表
在数据库里面新建一个表a_user,字段userid,username,password.并往表中插入几个条数据。
建立代码模板配置文件
(1)建立service.xml文件
在ext-ejb/src/com/ext/portlet 新建一个目录myuser,在目录下建立一个service.xml文件
文件内容为:
<?xml version="1.0"?>
<!DOCTYPE service-builder PUBLIC "-//Liferay//DTD Service Builder 4.0.0//EN"
"http://www.liferay.com/dtd/liferay-service-builder_4_0_0.dtd">
<service-builder root-dir=".." package-path="com.ext.portlet">
<portlet name="Reports" short-name="Reports">
<entity name="ReportsEntry" local-service="false" remote-service="true"
persistence-class="com.ext.portlet.reports.service.persistence.ReportsEntryPersistence">
<!-- PK fields -->
<column name="entryId" type="String" primary="true">
<!-- Audit fields -->
<column name="companyId" type="String">
<column name="userId" type="String">
<column name="userName" type="String">
<column name="createDate" type="Date">
<column name="modifiedDate" type="Date">
<!-- Other fields -->
<column name="name" type="String">
<!-- Order -->
<order by="asc">
<order-column name="name" case-sensitive="false">
</order>
<!-- Finder methods -->
<finder name="CompanyId" return-type="Collection">
<finder-column name="companyId">
</finder>
<finder name="UserId" return-type="Collection">
<finder-column name="userId">
</finder>
<!-- References -->
<reference package-path="com.liferay.portal" entity="User">
</entity>
<exceptions>
<exception>EntryName</exception>
</exceptions>
</service-builder>
<!--package-path是指我们即将建立portlet的上级目录-->
<!-- portlet name就是我们新建文件夹名称myuser,short-name没有作研究不太清楚使用途径-->
<!--entity name 是和我们即将建立的和数据库表a_user一一对应实体的类名,可以和数据库表名不同,
但为方便起见一般和表名保持一致-->
(2)修改ant文件,增加ant任务
建好service.xml文件后,我们在ext-ejb目录下打开build-perent.xml 在
<target name="build-service">
…….
</target>
下面添加任务
<target name="build-service-portlet-usertest">
<antcall target="build-service">
<param name="service.file"
value="src/com/ext/portlet/myuser/service.xml">
</antcall>
</target>
然后在myexlipse的ant视图里面打开ext-ejb目录下的build.xml执行build-service-portlet-usertest任务。
我们发现在ext-ejb/src/com/ext/portlet/myuser下面多了几个目录和文件。这是都是系统自动产生的
ebernate的实体类和持久化类。如果我们再细心些也可发现在ext-ejb\classes\META-INF目录下配置文件
都多些内容。系统已经自动将对应的实体类、持久化类、工具类等配置为相应的javabean、ejb、webservice等
。无疑节省了很多时间,而且减少我们人工配置的错误。
业务实现编码
现在我们要实现一个查询功能,将数据库中表名a_user中所有记录的username查询出来,并显示在前台。
打开myuser/service/Persistence下a_userPersistence.java文件,建立一个方法名为findAllUsername:
public List findAllUsername () throws SystemException {
Session session = null;
try {
session = openSession();
StringBuffer query = new StringBuffer();
query.append("FROM com.ext.portlet.myuser.model.a_user ");
Query q = session.createQuery(query.toString());
q.setCacheable(true);
return q.list();
} catch (HibernateException he) {
throw new SystemException(he);
} finally {
closeSession(session);
}
}
返回表a_user所有记录,并以list方式存储。题外话,一般系统已经自动产生了主要字段的查询方法,
我们可以直接拿来用或者稍作改动都可以使用。
按一般惯例,a_userPersistence一般是不暴露给外面类,我们都是通过它的一个持久化辅助类来调用。
打开a_userUtil.java,同样在里面增加方法findAllUsername
public static java.util.List findAllUsername ()
throws com.liferay.portal.SystemException {
return getPersistence().findAllUsername ();
}
然后我们在spring的service层同样增加一个方法。Service层的接口a_userLocalService里面增加一个函数
public List getAllUsers() throws SystemException;
在Service层接口a_userLocalService的实现a_userLocalServiceImpl.java增加对应方法,并调用持久层辅
助类userUtil方法findAllUsername
public List getAllUsers() throws SystemException {
return a_userUtil. findAllUsername ();
}
同样spring的service层 也是通过辅助类作为对外唯一入口,所以在a_userLocalServiceUtil里面增加一
个方法findAllUsername作为service层的方法findAllUsername的入口。
public static List getAllUsers() throws SystemException{
try{
a_userLocalService service = a_userLocalServiceFactory.getService();
return service.getAllUsers();
}catch (SystemException se) {
throw se;
}
catch (Exception e) {
throw new com.liferay.portal.SystemException(e);
}
}
需要注意的是service层接口对应具体实现是由工厂类指定。他们捆绑关系可以查看spring配置文件信息。
在执行ant 的build-service-portlet-usertest任务已经完成了。
在myuser/action目录下建立一个ViewUserAction.java文件,完成响应客户端请求。
public class ViewUsersAction extends PortletAction {
public ActionForward render(
ActionMapping mapping, ActionForm form, PortletConfig config,
RenderRequest req, RenderResponse res)
throws Exception {
if (req.getWindowState().equals(WindowState.NORMAL)) {
return mapping.findForward("portlet.ext.myuser.view");
}
else {
List users = a_userLocalServiceUtil.getAllUsers();
List usernames = new ArrayList();
for (int i=0;i<users.size();i++){
usernames.add( ((a_user) users.get(i)).getUsername());
}
req.setAttribute("users", usernames);
return mapping.findForward("portlet.ext.myuser.view_users");
}
}
}
里面大概功能是如果porlet的窗口状态时普通,则定向到一个叫portlet.ext.myuser.view的目标上。
如果窗口状态是最大化,那么就从调用userLocalServiceUtil,从数据库里面获取所有人员信息。
Portlet的生成
建立自己的portlet。在myuser下面新建文件UsersPortlet.java
public class UsersPortlet extends StrutsPortlet {
public void doView(RenderRequest req, RenderResponse res)
throws IOException, PortletException {
PortletPreferences prefs = req.getPreferences();
System.out.println(prefs.getValue("user", ""));
super.doView(req, res);
}
}
该portlet重载了doview方法。如果自己portlet对view和edit有自己特性,那么只要重载doview和doedit就可以了。
现在portlet的内容是空的,我们用jsp页面来展示用户名称方式来填充portlet里面内容。
在 ext-web/docroot/html/portlet/ext目录下建立目录myuser,并在myuser目录下建立init.jsp文件
<%@ include file="/html/common/init.jsp" %>
<portlet:defineObjects>
<% PortletPreferences prefs = renderRequest.getPreferences();
建立view.jsp文件:
<%@ include file="/html/portlet/ext/myuser/init.jsp" %>
<a href="<portlet:renderURL
windowState="<%= WindowState.MAXIMIZED.toString() %>">">
MyUser
<%= prefs.getValue("user", "") %>
</a>
该jsp内容是显示默认的初始用户名。具体值从初始化配置参数里获取。
建立view_users.jsp
<%@ include file="/html/portlet/ext/myuser/init.jsp" %>
<% List reports = (List)request.getAttribute("users");%>
<%
for (int i = 0; i < reports.size(); i++) {
String reportName = (String)reports.get(i);
%>
<%= reportName %><br>
<%
}
%>
该jsp页面目的是展示所有从数据库里面取出来的用户名。
Ok,完成以上工作后,我们整个portlet编码工作已经宣告结束,接下来的是配置portlet
参数工作。
Portlet的配置
是portlet配置信息文件存放Ext-web/web-inf目录下,在port-ext.xml文件里面添加
<portlet>
<portlet-name>EXT_users</portlet-name>
<display-name>myusers</display-name>
<portlet-class>com.ext.portlet.myuser.UsersPortlet</portlet-class>
<init-param>
<name>view-action</name>
<value>/ext/myuser/view_users</value>
</init-param>
<expiration-cache>0</expiration-cache>
<supports>
<mime-type>text/html</mime-type>
</supports>
<resource-bundle>com.liferay.portlet.StrutsResourceBundle</resource-bundle>
<portlet-preferences>
<preference>
<name>user</name>
<value>jack</value>
</preference>
</portlet-preferences>
<security-role-ref>
<role-name>power-user</role-name>
</security-role-ref>
<security-role-ref>
<role-name>user</role-name>
</security-role-ref>
</portlet>
<portlet-name>必须唯一,不得已有portlet名字冲突。<display-name>也必须唯一。
<portlet-class>指向我们的建立portlet类。
<name>view-action</name>里面值是指view这个action对应的actionurl。<portlet-preferences>
里面参数值是提供给这个portlet使用的参数初始值。这里配置是指portlet里面使用到参数名user的值是jack。
如portlet不需要初始值参数,则该项不需要配置。
在liferay-portlet-ext.xml文件里面添加
<portlet>
<portlet-name>EXT_users</portlet-name>
<struts-path>ext/myuser</struts-path>
<use-default-template>false</use-default-template>
</portlet>
<portlet-name>的值必须和portlet-ext.xml文件里面<portlet-name>值一致。
在liferay-display。Xml文件节点<category name="category.test">
下面添加
<portlet id="EXT_users"> id必须和portlet-ext里面的<portlet-name>一致。
在struts-config.xml文件里面添加内容:
<action path="/ext/myuser/view_users"
type="com.ext.portlet.myuser.action.ViewUsersAction">
<forward name="portlet.ext.myuser.view_1"
path="portlet.ext.myuser.view">
<forward name="portlet.ext.myuser.view_users_1"
path="portlet.ext.myuser.view_users">
</action>
就是说,当前台提交一个actionUrl为/ext/myuser/view_users请求的时候,由ViewUsersAction负责处理这个
action操作。后面2个forward指的是在ViewUsersAction定向返回请求目标页面。
…………
return mapping.findForward("portlet.ext.myuser.view_1");
………
return mapping.findForward("portlet.ext.myuser.view_users_1");
findForward的值为避免与其他findForward值冲突,一般将包名也带上,保证不会重名。
在tiles-defs.xml文件里面添加内容:
<definition name="portlet.ext.myuser.view" extends="portlet">
<put name="portlet_content" value="/portlet/ext/myuser/view.jsp">
</definition>
<definition name="portlet.ext.myuser.view_users" extends="portlet">
<put name="portlet_content" value="/portlet/ext/myuser/view_users.jsp">
</definition>
该name的值即随同struct-config.xml配置信息里面forward参数path值对应的,指向真正的目标页面。
最后我们在ext-ejb/classes/content目录下language-ext.properties文件里面增加内容:
javax.portlet.title.EXT_user=MyUsers
即portlet显示出来时候,在portlet上面标题信息。
Portlet常见问题
1. 运行提示portlet path 找不到,则一般是liferay-port-ext文件里面portlet的struts–path有问题。
2. 启动提示jaas.config错误,没有在tomcat的jdk参数配置jaas.config文件或配置路径不对
3. 提示html/../..找不到,一般是struts-config文件里面path路径有问题。
4. 有执行和数据库存取数据时候,提示“columnname_”字段不存在,去修改ext-hbm.xml文件,ant执行
build service任务时候,产生ext-hbm.xml信息有时会不准确,将对应的<property name="columnname"
column="columnname_ ">的column调整为数据库对应正确的字段名。
5. 大家在清除不用的portlet时候,请先登录系统,将不用的portlet关闭,然后再删除或屏蔽对应的代码。
不然直接删除或屏蔽代码,重新启动后,会提示portlet找不到。注册后的portlet会写信息到数据库中。