Liferay hook working with Spring + MyBatis(Updated 3 ways now)

In some cases, we need to customize Liferay. In my case, I choose hook to do that. But it ran into an issue how to get beans in the service class.

For example:

public class MyOrganizationLocalServiceImpl extends OrganizationLocalServiceWrapper {

	public MyOrganizationLocalServiceImpl(OrganizationLocalService organizationLocalService) {
		super(organizationLocalService);
	}
	
	
	public Organization updateOrganization(long companyId, long organizationId,
			long parentOrganizationId, String name, String type, boolean recursable, long regionId,
			long countryId, int statusId, String comments, boolean site,
			ServiceContext serviceContext) throws PortalException, SystemException {

//...more


This is my own service class, I have to get the beans which will use to connect the database and do some operation. Because OrganizationLocalServiceWrapper doesn't have default constructor,  we can't ask Spring to initialize the class for us. That means we can't use Constructor or setting injection in the class. 

Actually, when you deploy the project, tomcat will read web.xml, then tomcat will initialize beans for use if we do settings like this:

<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>/WEB-INF/SpringContextConfiguration.xml</param-value>
	</context-param>

	<listener>
		<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
	</listener>

	<listener>
		<listener-class>com.liferay.portal.kernel.servlet.HookContextListener</listener-class>
	</listener>
Even though all beans are initialized, I can't get in service class, it doesn't work on my case. 

The only way I can get beans is read the SpringContextConfiguration.xml in the service class. Then use ApplicationContext to get beans. Hard code.

private static ApplicationContext context = new ClassPathXmlApplicationContext("../SpringContextConfiguration.xml");
private IOrganizationStatusManager organizationStatusManager = context.getBean(
			"organizationStatusManager", IOrganizationStatusManager.class);

This is my solution to do that, if anyone has good solution, please let me know. Thanks in advance!

--------------------------------------------------------------------The Second Way-----------------------------------------------------------------------------------------------------

Here is to show another way, a better way to do this. I need to thanks my coworker Bin. He helped me figure it out.

The basic idea is to use a spring util class, let me show you the code.

SpringUtil.java. The class is singleton.

public class SpringBeanUtil {
	
private static SpringBeanUtil instance = new SpringBeanUtil();
	
	private static IOrganizationStatusManager organizationStatusManager;
	
	private SpringBeanUtil () {}

	public static SpringBeanUtil getInstance() {
		return instance;
	}
	
	public void setInstance(SpringBeanUtil newInstance) {
		instance = newInstance;
	}

	public IOrganizationStatusManager getOrganizationStatusManager() {
		return organizationStatusManager;
	}
	
	public void setOrganizationStatusManager(IOrganizationStatusManager organizationStatusManager) {
		SpringBeanUtil.organizationStatusManager = organizationStatusManager;
	}
	
}

In our springcontext.xml, we need to define the beans, it doesn't work by using annotation. We have to explicitly wire the beans.

<bean id="springBeanUtil" class="org.myproject.organizationhook.util.SpringBeanUtil">
		<property name="organizationStatusManager" ref="organizationStatusManager"></property>
</bean>

OrganizationStatusManager.java

@Service("organizationStatusManager")
@Transactional("organizationTransactionManager")
public class OrganizationStatusManager implements IOrganizationStatusManager {

	@Autowired
	@Qualifier("organizationStatusDao")
	private IOrganizationStatusDao organizationStatusDao;

	//isDeleted = 0 means the organization isn't deleted
	public int addOrganizationStatus(long organizationId) {		
		return null;
	}

	public String getSNByOrganizationId(long organizationId) {
		return null;
	}

	public long countOrgStatuses() {
		return 0L;
	}

	public void updateOrganizationStatus(long organizationId) {
	}

	public int addLastUpdateStatus() {	
		return 0;
	}

	public void deleteOrganizationStatus(long organizationId) {	
	}

}

The last thing we need to do is when we deploy the hook project, load the configuration file. We add listener in web.xml

<context-param>
	<param-name>contextConfigLocation</param-name>
	<param-value>/WEB-INF/springcontext.xml</param-value>
</context-param>


<listener>
	<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
In web.xml, if we don't specify context-param to give a specific name for the file, the default name is applicationContext.xml

Now, in our MyOrganizationLocalServiceImpl.java, we use the IOrganizationManager class like this:



That's all! The tricky thing here is we can't add annotation on SpringBeanUtil, even though we add that, in MyOrganizationLocalServiceImpl class also get null. We have to explicit wire those beans in springcontext.xml.

public class MyOrganizationLocalServiceImpl extends OrganizationLocalServiceWrapper {
	
private IOrganizationStatusManager organizationStatusManager = SpringBeanUtil.getInstance().getOrganizationStatusManager();

//...more

The second way is better than the first one. We don't take care of the spring beans manually, tomcat takes care of that.

-------------------------------------------------------------The Third Way----------------------------------------------------------

I just learned a new way from my co-worker Bin to get the bean. This would be the best way to do that. Spring is so powerful to meet our requirements.

This way is very easy, you just need to write another class and directly call it. We need to get the help of BeanFactory.

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.stereotype.Component;

@Component("beanFactoryUtil")
public class BeanFactoryUtil implements BeanFactoryAware{
	
	private static BeanFactory beanFactory = null;

	public void setBeanFactory(BeanFactory beanFactory1) throws BeansException {
		beanFactory = beanFactory1;
	}
	
	public static BeanFactory getBeanFactory(){
		return beanFactory;
	}

}

This class is only used to get BeanFactory, then we use it to get beans in our util class:

private IOrganizationStatusManager organizationStatusManager = (IOrganizationStatusManager) BeanFactoryUtil.getBeanFactory().getBean("organizationStatusManager");
That's all. It's really easy right.


Note:

If you're developing on Servlet, you don't need to write the BeanFactoryUtil class, you can directly get beans like this:

BeanFactory bf = WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext());

I tried to get ServletContext in my wrapper class, but it throws Exception which I didn't find a good answer until now.

PortletBag portletBag = com.liferay.portal.kernel.portlet.PortletBagPool.get(serviceContext.getPortletId());
ServletContext servletContext = portletBag.getServletContext();
BeanFactory bf = WebApplicationContextUtils.getRequiredWebApplicationContext(servletContext);


Exception message:

21:00:14,035 ERROR [render_portlet_jsp:154] java.lang.IllegalStateException: Context attribute is not of type WebApplicationContext: Root WebApplicationContext: startup date [Fri Dec 21 20:25:57 GMT 2012]; root of context hierarchy
	at com.rujuan.organizationhook.custom.MyOrganizationLocalServiceImpl.updateOrganization(MyOrganizationLocalServiceImpl.java:63)
	at com.liferay.portal.kernel.bean.ClassLoaderBeanHandler.invoke(ClassLoaderBeanHandler.java:54)
	at com.liferay.portal.spring.aop.ServiceBeanMethodInvocation.proceed(ServiceBeanMethodInvocation.java:112)
	at com.liferay.portal.spring.transaction.TransactionInterceptor.invoke(TransactionInterceptor.java:71)
	at com.liferay.portal.spring.aop.ServiceBeanMethodInvocation.proceed(ServiceBeanMethodInvocation.java:108)
	at com.liferay.portal.spring.aop.ServiceBeanAopProxy.invoke(ServiceBeanAopProxy.java:211)
	at com.liferay.portal.service.impl.OrganizationServiceImpl.updateOrganization(OrganizationServiceImpl.java:587)
	at com.liferay.portal.spring.aop.ServiceBeanMethodInvocation.proceed(ServiceBeanMethodInvocation.java:112)
	at com.liferay.portal.spring.transaction.TransactionInterceptor.invoke(TransactionInterceptor.java:71)
	at com.liferay.portal.spring.aop.ServiceBeanMethodInvocation.proceed(ServiceBeanMethodInvocation.java:108)
	at com.liferay.portal.spring.aop.ServiceBeanAopProxy.invoke(ServiceBeanAopProxy.java:211)
	at com.liferay.portal.service.OrganizationServiceUtil.updateOrganization(OrganizationServiceUtil.java:427)
	at com.liferay.portlet.usersadmin.action.EditOrganizationAction.updateOrganization(EditOrganizationAction.java:239)
	at com.liferay.portlet.usersadmin.action.EditOrganizationAction.processAction(EditOrganizationAction.java:86)
	at com.liferay.portal.struts.PortletRequestProcessor.process(PortletRequestProcessor.java:175)
	at com.liferay.portlet.StrutsPortlet.processAction(StrutsPortlet.java:212)
	at com.liferay.portlet.FilterChainImpl.doFilter(FilterChainImpl.java:70)
	at com.liferay.portal.kernel.portlet.PortletFilterUtil.doFilter(PortletFilterUtil.java:48)
	at com.liferay.portlet.InvokerPortletImpl.invoke(InvokerPortletImpl.java:651)
	at com.liferay.portlet.InvokerPortletImpl.invokeAction(InvokerPortletImpl.java:686)
The reason is the root of ServletContext I passed in is not WebApplicationContext rather than PortletApplicationContext.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Liferay 使用手册是指Liferay平台的一份详细说明文档,用于指导用户如何正确安装、配置和使用Liferay平台的各项功能和特性。 Liferay是一种开源的企业门户解决方案,它提供了许多功能和工具,方便用户快速搭建和管理自己的网站、门户或应用程序。然而,对于不熟悉Liferay的用户来说,往往需要一个指导手册来帮助他们更好地理解和使用平台。 Liferay 使用手册通常会包含以下内容: 1. 安装和部署指南:介绍如何正确安装和部署Liferay平台,并提供相应的操作步骤和注意事项。 2. 配置和管理:详细说明如何进行Liferay平台的配置和管理,包括用户管理、权限设置、主题和布局等。 3. 内容管理:介绍如何创建和管理网站的内容,包括新闻、博客、论坛等功能,并提供相应的操作示例。 4. 社交协作:解释如何使用Liferay平台进行协作和合作,包括团队和项目管理、文档共享、日历和通知等。 5. 应用程序开发:指导开发人员如何使用Liferay平台进行应用程序的开发和集成,包括使用API和插件的方式。 6. 故障排除和支持:提供常见问题的解答和故障排除的方法,以及如何获取更多的支持和帮助。 总之,Liferay 使用手册是一份重要的指导文档,它可以帮助用户快速入门和掌握Liferay平台的使用方法,提高工作效率和用户体验。用户可以根据手册中提供的步骤和示例,了解和掌握各个功能的使用方式,从而更好地利用Liferay平台来满足自己的需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值