Apache Pluto和PHP集成示例教程
创建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简介,以了解如何完成这些重要任务。