Apache Pluto和PHP集成示例教程

时间:2020-02-23 14:29:40  来源:igfitidea点击:

创建PHP Portlet并非易事,因为没有为其创建标准规范。
但是,当要在PHP和Java之间进行集成时,您可能主要希望:

  • 在PHP页面内执行Java代码。
    (使用Java Bridge,稍后再讨论)。

  • 通过基于Java的容器(JVM)执行PHP页面。
    (使用Quercus库)。

实际上,本教程旨在涵盖第二个选择,因为稍后将讨论第一个选择。
实际上,您可能会在Apache Pluto内找到指向PHP桥的链接,但不幸的是,它被视为过时的API,因此不再可用。
您将无法以JAR或者Maven库的形式找到上述所有库。

本教程将为您提供一种集成,您可能会发现它是在Portlet应用程序中利用PHP代码的非常有用的方法。
我们将按照与使用JSP和Servlet教程开发Portlet一样的方式来组织Portlet,Servlet和PHP页面,以实现员工注册过程。

为了在JVM中执行PHP页面,我们使用了Quercus库,该库被视为PHP语言的基于Java的实现。
它已经包含在许多PHP模块和扩展中,例如PDF,MySQL,JSON等。

但是,假定的员工注册示例将在使用标准Portlet处理客户请求并将其委托到所需视图(PHP页面)的过程中遵循MVC概念,一旦用户激活了注册操作,则提交的表单应由为此已经创建的业务Servlet,然后应注册员工。

注册操作成功完成后,将显示一条确认消息。
如果您遇到例外情况,则应以发生错误的原因显示一条错误消息。

无论操作是否成功完成,用户都将能够再次导航到注册员工视图中以进行另一次试用。

员工表

本部分将向您显示用于保留注册员工的员工表。

employee.sql

CREATE TABLE `employee` (
`EMP_ID` int(11) NOT NULL AUTO_INCREMENT,
`EMP_NAME` varchar(45) DEFAULT NULL,
`EMP_JOB` varchar(45) DEFAULT NULL,
`EMP_SALARY` int(11) DEFAULT NULL,
PRIMARY KEY (`EMP_ID`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;

员工模式

因此,应定义一个Employee对象模型来保存在注册过程中来回传递的员工信息。

Employee.java

package com.theitroad.data;

public class Employee {
	private int id;
	private String name;
	private String job;
	private int salary;

	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 getJob() {
		return job;
	}

	public void setJob(String job) {
		this.job = job;
	}

	public int getSalary() {
		return salary;
	}

	public void setSalary(int salary) {
		this.salary = salary;
	}
}

PHP视图

与为JSP提供的示例类似,应使用一组PHP页面来处理视图。
主要地,我们有三个不同的视图,员工注册,成功确认和失败确认是您处理员工注册过程时要处理的唯一视图。

register.php

<?php
$actionUrl = "?";
$renderUrl = "?";

foreach($_GET as $key=>$val){
	if($key == "actionUrl"){
		$actionUrl = $val;
	}
}
?>
<html>
	<body>
		<form action="<?php echo $actionUrl?>" method="POST">
			<table>
				<tr>
					<td>Enter ID:</td>
					<td><input name="employeeID"</td>
				</tr>
				<tr>
					<td>Enter name:</td>
					<td><input name="employeeName"</td>
				</tr>
				<tr>
					<td>Enter job:</td>
					<td><input name="employeeJob"</td>
				</tr>
				<tr>
					<td>Enter salary:</td>
					<td><input name="employeeSalary"</td>
				</tr>
				<tr>
					<td colspan="2">
						<input type="submit" value="Register"
					</td>
				</tr>
			</table>
		</form>
	</body>
</html>

success.php

<?php 

$renderUrl = "?";

foreach($_GET as $key=>$val){
	if($key == "renderUrl"){
		$renderUrl = $val;
	}
}
?>
<html>
	<body>
		<table>
			<tr>
				<td>
					Congratulations, employee registration operation has been finished successfully !
				</td>
			</tr>
		</table>
		<a href="<?php echo $renderUrl?>">Register Another</a>
	</body>
</html>

failure.php

<?php 

$renderUrl = "?";
$exception = "?";

foreach($_GET as $key=>$val){
	if($key == "renderUrl"){
		$renderUrl = $val;
	}
	else if($key == "exception"){
		$exception = $val;
	}
}
?>
<html>
	<body>
		<table>
			<tr>
				<td>
					<span style="color: red;">
						Unfortunately, employee registration operation hasn't been finished successfully !
					
				</td>
			</tr>
			<tr>
				<td>For cause:<?php echo $exception?></td>
			</tr>
		</table>
		<a href="<?php echo $renderUrl?>">Try Again</a>
	</body>
</html>

只是,希望您注意到我们在提供的视图中有一个PHP代码段,并且这些代码段将完全由使用的JVM(即Apache Pluto)处理。

Portlet部署描述符

在portlet.xml文件下面找到可帮助您的Portlet容器识别您的Portlet的文件。

portlet.xml

<?xml version="1.0" encoding="UTF-8"?>

<portlet-app xmlns="https://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd"
	version="2.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="https://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd">
	<portlet>
		<display-name>Register Employee</display-name>
		<portlet-name>RegisterEmployee</portlet-name>
		<portlet-class>com.theitroad.portlet.RegisterEmployeePortlet
		</portlet-class>
		<description>Employee Registration</description>
		<supports>
			<mime-type>text/html</mime-type>
			<portlet-mode>VIEW</portlet-mode>
		</supports>
		<portlet-info>
			<title>Employee Registration</title>
			<keywords>employee, registration</keywords>
			<short-title>Employee Registration</short-title>
		</portlet-info>
	</portlet>
</portlet-app>

您已经提到,用作开发Portlet的其他片段不是标准片段。

注册员工门户

RegisterEmployeePortlet.java

package com.theitroad.portlet;

import java.io.IOException;

import javax.portlet.ActionRequest;
import javax.portlet.ActionResponse;
import javax.portlet.GenericPortlet;
import javax.portlet.PortletException;
import javax.portlet.PortletRequestDispatcher;
import javax.portlet.RenderRequest;
import javax.portlet.RenderResponse;

public class RegisterEmployeePortlet extends GenericPortlet{

	public void doView(RenderRequest request, RenderResponse response) throws PortletException, IOException {
		if(request.getParameter("status") == null){
			PortletRequestDispatcher dispatcher = this.getPortletContext().getRequestDispatcher("/register/register.php?actionUrl="+
					response.createActionURL());
			dispatcher.include(request, response);
		}
		else {
			if(request.getParameter("status").equals("success")){
				PortletRequestDispatcher dispatcher = this.getPortletContext().getRequestDispatcher("/register/success.php?renderUrl="+
						response.createRenderURL());
				dispatcher.include(request, response);
			}
			else {
				PortletRequestDispatcher dispatcher = this.getPortletContext().getRequestDispatcher("/register/failure.php?renderUrl="+
						response.createRenderURL()+"&exception="+request.getParameter("exception"));
				dispatcher.include(request, response);
			}
		}
	}

	public void processAction(ActionRequest request, ActionResponse response) throws PortletException, IOException{
		//Create request dispatcher
		PortletRequestDispatcher dispatcher =  this.getPortletContext().getNamedDispatcher("RegisterEmployeeServlet");
		try {
			//Include
			dispatcher.include(request, response);
			//Set render parameter
			response.setRenderParameter("status", "success");
		}
		catch(Exception ex){
			//Set render parameter
			response.setRenderParameter("status", "failed");
			response.setRenderParameter("exception", ex.getMessage());
		}
	}
}

注册员工Servlet

RegisterEmployeeServlet.java

package com.theitroad.servlet;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;

import com.theitroad.dao.EmployeeDAO;
import com.theitroad.data.Employee;

public class RegisterEmployeeServlet extends HttpServlet {

	private static final long serialVersionUID = 1L;
	Logger logger = Logger.getLogger(RegisterEmployeeServlet.class);

  public RegisterEmployeeServlet() {
      super();
  }

	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		//Create employee
		Employee employee = new Employee();
		//Fill in required data from the request sent
		employee.setId(Integer.parseInt(request.getParameter("employeeID")));
		employee.setName(request.getParameter("employeeName"));
		employee.setJob(request.getParameter("employeeJob"));
		employee.setSalary(Integer.parseInt(request.getParameter("employeeSalary")));
		try {
			//Asking employeeDAO creating the employee against registered database
			Employee createdEmployee = EmployeeDAO.getInstance().createEmployee(employee);
			//Print out the created employee information
			logger.info("Employee Created"+createdEmployee);
		} catch (Exception e) {
			//Log the exception
			logger.error("Employee Creation Failed", e);
			//Throw another exception for notifying the Portlet
			throw new ServletException(e);
		}
	}

}

部署描述符和Maven构建文件

如前所述,Quercus用于解释JVM内部的PHP代码,因此,在Maven文件中将包含执行JVM内部PHP代码所需的所有必需库。

pom.xml

<project xmlns="https://maven.apache.org/POM/4.0.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/maven-v4_0_0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.theitroad</groupId>
	<artifactId>PHPBridge</artifactId>
	<packaging>war</packaging>
	<version>0.0.1-SNAPSHOT</version>
	<name>PHPBridge</name>
	<url>https://maven.apache.org</url>
	<properties>
		<deployFolder>D:/Apache Pluto/pluto-2.0.3/webapps</deployFolder>
	</properties>

	<repositories>
		<repository>
			<id>caucho</id>
			<name>Caucho</name>
			<url>https://caucho.com/m2</url>
			<layout>default</layout>
			<snapshots>
				<enabled>false</enabled>
			</snapshots>
		</repository>
	</repositories>
	<dependencies>
		<!-- Java Portlet Specification V2.0 -->
		<dependency>
			<groupId>org.apache.portals</groupId>
			<artifactId>portlet-api_2.0_spec</artifactId>
			<version>1.0</version>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>servlet-api</artifactId>
			<version>2.4</version>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>jsp-api</artifactId>
			<version>2.0</version>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>commons-fileupload</groupId>
			<artifactId>commons-fileupload</artifactId>
			<version>1.3</version>
		</dependency>
		<dependency>
			<groupId>log4j</groupId>
			<artifactId>log4j</artifactId>
			<version>1.2.17</version>
		</dependency>
		<dependency>
			<groupId>org.apache.pluto</groupId>
			<artifactId>pluto-taglib</artifactId>
			<version>1.1.7</version>
		</dependency>
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>5.1.32</version>
		</dependency>
		<dependency>
			<groupId>com.caucho</groupId>
			<artifactId>resin</artifactId>
			<version>4.0.30</version>
		</dependency>
	</dependencies>
	<build>
		<finalName>${project.artifactId}</finalName>
		<plugins>
			<!-- bind 'pluto2:assemble' goal to 'process-resources' lifecycle -->
			<!-- This plugin will read your portlet.xml and web.xml and injects required
				lines -->
			<plugin>
				<groupId>org.apache.portals.pluto</groupId>
				<artifactId>maven-pluto-plugin</artifactId>
				<version>2.1.0-M3</version>
				<executions>
					<execution>
						<phase>generate-resources</phase>
						<goals>
							<goal>assemble</goal>
						</goals>
					</execution>
				</executions>
			</plugin>
			<!-- configure maven-war-plugin to use updated web.xml -->
			<!-- This plugin will make sure your WAR will contain the updated web.xml -->
			<plugin>
				<artifactId>maven-war-plugin</artifactId>
				<version>2.1.1</version>
				<configuration>
					<webXml>${project.build.directory}/pluto-resources/web.xml</webXml>
				</configuration>
			</plugin>
			<plugin>
				<artifactId>maven-antrun-plugin</artifactId>
				<executions>
					<execution>
						<id>copy</id>
						<phase>integration-test</phase>
						<configuration>
							<tasks>
								<copy file="target/${project.artifactId}.war" tofile="${deployFolder}/${project.artifactId}.war" 
							</tasks>
						</configuration>
						<goals>
							<goal>run</goal>
						</goals>
					</execution>
					<execution>
						<id>delete</id>
						<phase>clean</phase>
						<configuration>
							<tasks>
								<delete file="${deployFolder}/${project.artifactId}.war" 
								<delete dir="${deployFolder}/${project.artifactId}" 
							</tasks>
							<detail>true</detail>
						</configuration>
						<goals>
							<goal>run</goal>
						</goals>
					</execution>
				</executions>
			</plugin>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>3.1</version>
				<configuration>
					<source>1.6</source>
					<target>1.6</target>
				</configuration>
			</plugin>
		</plugins>
	</build>
</project>

您应该注意,已经为您提供了用于解释PHP目的的树脂库。
实际上,QuercusServlet可以做到这一点,因此,您必须在Web部署描述符中对其进行配置。
因此,我们将其添加到部署描述符中,该描述符应如下所示:

web.xml

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "https://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
	<display-name>Employee Registration</display-name>
	<servlet>
		<servlet-class>com.theitroad.servlet.RegisterEmployeeServlet</servlet-class>
		<servlet-name>RegisterEmployeeServlet</servlet-name>
	</servlet>
	<servlet-mapping>
		<servlet-name>RegisterEmployeeServlet</servlet-name>
		<url-pattern>/registerEmployeeServlet</url-pattern>
	</servlet-mapping>
	<taglib>
		<taglib-uri>https://java.sun.com/portlet</taglib-uri>
		<taglib-location>/WEB-INF/portlet.com</taglib-location>
	</taglib>
	<servlet>
		<servlet-name>Quercus Servlet</servlet-name>
		<servlet-class>com.caucho.quercus.servlet.QuercusServlet</servlet-class>
	</servlet>
	<servlet-mapping>
		<servlet-name>Quercus Servlet</servlet-name>
		<url-pattern>*.php</url-pattern>
	</servlet-mapping>
</web-app>

如您所见,任何对PHP资源的请求都应触发Quercus Servlet处理发起的请求。
该Servlet将读取请求的资源并对其进行解释,以为您的浏览器返回纯HTML代码。

EmployeeDAO和ConnectionUtility

为求简单,我们开发了EmployeeDAO和ConnectionUtility类来处理所有数据库操作。

ConnectionUtility.java

package com.theitroad.dao.utility;

import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Properties;

public class ConnectionUtility {

	private static ConnectionUtility connectionUtiliy = null;

	private Connection connection = null;

	private ConnectionUtility() {
	}

	public static ConnectionUtility getInstance() throws IOException, IllegalAccessException, SQLException, ClassNotFoundException{
		//Synchronized against connectionUtility instance
		synchronized(ConnectionUtility.class){
			//Check whether the connectionUtility is null or not
			if(connectionUtiliy == null){
				//Create a properties instance
				Properties properties = new Properties();
				//Load properties from classpath
				properties.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("connection.properties"));
				//Set connection with connectionUtility
				connectionUtiliy = new ConnectionUtility();
				//Load driver class
				Class.forName("com.mysql.jdbc.Driver");
				//Create connection
				connectionUtiliy.setConnection(DriverManager.getConnection("jdbc:mysql://localhost:3306/theitroad", properties));
			}
			return connectionUtiliy;
		}
	}

	public Connection getConnection() throws ClassNotFoundException, SQLException, IOException {
		if(connection.isClosed()){
			//Create a properties instance
			Properties properties = new Properties();
			//Load properties from classpath
			properties.load(Thread.currentThread().getContextClassLoader().getResourceAsStream("connection.properties"));
			//Load driver class
			Class.forName("com.mysql.jdbc.Driver");
			//Create connection
			connectionUtiliy.setConnection(DriverManager.getConnection("jdbc:mysql://10.10.90.3:3306/theitroad", properties));
		}
		return connection;
	}

	public void setConnection(Connection connection) {
		this.connection = connection;
	}

}

EmployeeDAO.java

package com.theitroad.dao;

import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

import com.theitroad.dao.utility.ConnectionUtility;
import com.theitroad.data.Employee;

public class EmployeeDAO {

	public static EmployeeDAO employeeDAO = null;

	private EmployeeDAO(){

	}

	public static EmployeeDAO getInstance(){
		synchronized(EmployeeDAO.class){
			if(employeeDAO == null){
				employeeDAO = new EmployeeDAO();
			}

		}
		return employeeDAO;
	}

	public Employee createEmployee(Employee employee) throws SQLException, IllegalAccessException, IOException, ClassNotFoundException{
		//Get connection instance
		Connection connection = ConnectionUtility.getInstance().getConnection();
		//Create Prepared Statement
		PreparedStatement query = connection.prepareStatement("INSERT INTO EMPLOYEE VALUES (?,?,?,?)");
		//Set variables
		query.setInt(1, employee.getId());
		query.setString(2, employee.getName());
		query.setString(3, employee.getJob());
		query.setInt(4, employee.getSalary());

		try {
			//Execute
			query.execute();
			//Return employee instance
			return employee;
		}
		catch(Exception e){
			//Close statement
			query.close();
			//Close connection
			connection.close();
			//Throw another exception for notifying the Servlet
			throw new SQLException(e);
		}
	}

	public boolean deleteEmployee(Employee employee){
		return false;
	}

	public boolean updateEmployee(Employee employee, int employeeId){
		return false;
	}
}

员工注册演示

现在,该看一下上面开发的代码的结果了,但是在进入之前,您应该创建一个名为theitroad的Portal页面,然后将WAR部署到Apache Pluto Portlet容器中。
如果您以前从未尝试过,请务必返回我们的Apache Pluto简介,以了解如何完成这些重要任务。