Apache Pluto Portlet&Struts 2集成示例教程
在较早的教程中,我们开发了不同类型的Portlet。
Portlet是一次使用JSP和Servlet开发的,然后我们学习了JSF与Portlet的结合使用。
这次,我们将使用另一个著名的框架(例如Apache Struts)来开发Portlet。
Srigi框架是基于MVC的框架,我们已经在Apache Struts上介绍了很多主题,您可以参考所有这些主题,但这是您第一次将Struts应用程序部署到Apache Pluto等Portlet容器中。
您可能会使用Apache本身已经维护的Apache Struts Bridge。
但是,本教程将使用您之前实现的相同应用程序(员工注册表格),但使用Struts2框架。
该应用程序的主要目的是帮助您了解将应用程序部署并正确运行到任何符合JSR-168/JSR-286的Portlet容器上所需的所有详细信息。
员工表设计
本节将向您说明什么是"雇员表"以及使用了哪些列。
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"实体(模型),该实体将用于保存在应用程序和数据库存储之间来回传输的数据。
package com.theitroad.data; public class Employee { private String id; private String name; private String job; private String salary; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getSalary() { return salary; } public void setSalary(String salary) { this.salary = salary; } 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; } }
使用Eclipse IDE创建模板应用程序
通过使用Apache Struts原型,您可以节省时间,而不用自己去创建项目。
以下步骤将帮助您轻松创建Struts Portlet应用程序。
将远程原型目录https://struts.apache.org/添加到您的Maven原型中。
创建一个新的Maven项目。
这次,您将停止使用目录选择,而不必使用所有目录,而必须选择已注册的目录。填写所有必需的信息,GroupId,ArtifactId,版本和软件包。
单击完成,然后等待Eclipse在Project Explorer中显示创建的应用程序。
尽管应用程序创建成功,但是由于原型的Maven依赖关系未得到更新,因此可能需要进行一些手动调整。
因此,您可能会在创建的应用程序中发现一些错误。删除com.theitroad软件包下的所有不需要的Java文件。
删除WEB-INF/jsp下所有不需要的JSP文件/文件夹。
修改Maven依赖项
Maven依赖项文件已修改为提供两个所需功能:
为Struts2及其相关的Portlet容器Bridge添加必需的依赖项。
添加所有必需的Apache Pluto随附文件,这些文件将引导我们在Apache Pluto本身上进行良好的部署。
pom.xml
<?xml version="1.0" encoding="UTF-8"?> <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>EmployeeRegistration-StrutsBridge</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>war</packaging> <name>EmployeeRegistration-StrutsBridge</name> <properties> <struts2.version>2.3.16.3</struts2.version> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <deployFolder>D:/Apache Pluto/pluto-2.0.3/webapps</deployFolder> </properties> <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> <!-- Apache Struts & Core --> <dependency> <groupId>org.apache.struts</groupId> <artifactId>struts2-core</artifactId> <version>${struts2.version}</version> </dependency> <dependency> <groupId>org.apache.struts</groupId> <artifactId>struts2-config-browser-plugin</artifactId> <version>${struts2.version}</version> </dependency> <dependency> <groupId>org.apache.struts</groupId> <artifactId>struts2-portlet-plugin</artifactId> <version>2.3.16.3</version> </dependency> <dependency> <groupId>org.apache.struts</groupId> <artifactId>struts2-junit-plugin</artifactId> <version>${struts2.version}</version> <scope>test</scope> </dependency> <!-- Commons logging --> <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.1.3</version> </dependency> <!-- Log4j --> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.5</version> <scope>test</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> <!-- Apache Struts Portlet Bridge --> <dependency> <groupId>org.apache.portals.bridges</groupId> <artifactId>portals-bridges-struts-1.2.7</artifactId> <version>1.0.4</version> </dependency> <!-- MySQL driver --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.32</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.7</source> <target>1.7</target> </configuration> </plugin> </plugins> </build> </project>
员工注册视图
如您所知,Apache Struts将JSP视为一种视图技术,因此我们将添加三个不同的文件,分别是register.jsp,success.jsp和failure.jsp。
根据Apache Struts Archetype,文件将添加到WEB-INF/jsp/employee文件夹下。
register.jsp
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%> <%@ taglib prefix="s" uri="/struts-tags" %> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "https://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> <title>Register Employee</title> </head> <body> <s:form action="register"> <s:textfield name="id" label="Identifier"></s:textfield> <s:textfield name="name" label="Name"></s:textfield> <s:textfield name="job" label="Job"></s:textfield> <s:textfield name="salary" label="Salary"></s:textfield> <s:submit value="Register"></s:submit> </s:form> </body> </html>
failure.jsp
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%> <%@ taglib prefix="s" uri="/struts-tags" %> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "https://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> <title>Failure</title> </head> <body> <span style="color:red">Unfortunately! The Employee hasn't been registered successfully </br> <a href="<s:url action="index" portletMode="view"">Try Again!</a> </body> </html>
success.jsp
<%@ page language="java" contentType="text/html; charset=ISO-8859-1" pageEncoding="ISO-8859-1"%> <%@ taglib prefix="s" uri="/struts-tags" %> <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "https://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1"> <title>Success</title> </head> <body> <span style="color:green">Congratulations! The Employee has been registered successfully <br <a href="<s:url action="index" portletMode="view"">Register Another</a> </body> </html>
您已经注意到,我们使用了Struts Tag库来提供表单组件及其相关参数。
如果您对Struts不太满意,那么由于它的框架非常优雅,您可以回到这里阅读一些有关它的文章。
Struts标记库提供了一个<url 标记,用于创建基于Struts的链接。
基于Struts的链接是一种使用Struts框架词汇之类的动作的链接。
您应该注意的一件重要事情是,用于操作的表单的操作属性是名称。
该名称将由" struts.xml"文件提供,稍后将进行讨论。
注册动作
您可能已经知道Struts是基于动作的框架。
因此,每个表单提交都应委派给基于动作的类,该类已实现为从DefaultActionSupport类扩展的。
在RegisterAction
Struts动作类之后。
package com.theitroad.action; import java.io.IOException; import java.sql.SQLException; import javax.portlet.PortletPreferences; import org.apache.log4j.Logger; import org.apache.struts2.dispatcher.DefaultActionSupport; import org.apache.struts2.portlet.interceptor.PortletPreferencesAware; import com.theitroad.dao.EmployeeDAO; import com.theitroad.data.Employee; public class RegisterAction extends DefaultActionSupport implements PortletPreferencesAware { private static Logger logger = Logger.getLogger(RegisterAction.class); private static final long serialVersionUID = 1L; private PortletPreferences preferences; private String id; private String name; private String job; private String salary; public PortletPreferences getPreferences() { return preferences; } public void setPreferences(PortletPreferences preferences) { this.preferences = preferences; } @Override public void setPortletPreferences(PortletPreferences prefs) { this.preferences = prefs; } @Override public String execute() throws Exception { try { Employee employee = new Employee(); employee.setId(id); employee.setName(name); employee.setJob(job); employee.setSalary(salary); //Register Employee employee = EmployeeDAO.getInstance().createEmployee(employee); logger.debug("Employee Has Registered"); return "SUCCESS"; } catch (IllegalAccessException | ClassNotFoundException | SQLException | IOException e) { logger.debug("Registration Process Has Failed",e); return "FAILURE"; } } public String getId() { return id; } public void setId(String 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 String getSalary() { return salary; } public void setSalary(String salary) { this.salary = salary; } }
这里是对RegisterAction
类的详细说明:
请注意,类的属性ID,名称,工作和薪水与" register.jsp"页面提供的这些参数的名称相似。
" RegisterAction"已经覆盖了" execute"方法,用于服务于员工注册。
Struts框架会将所有表单的参数与动作类中的那些对应参数绑定在一起。
ID,姓名,工作和薪水将自动传递。RegisterAction使用EmployeeDAO(我们之前介绍的相同的实用程序类,它将处理所有数据库操作代码)注册员工实例。
如果注册过程失败,Struts框架会将您带到失败页面。
一旦成功完成注册,Struts框架页面就会将您重定向到成功页面。
Struts应用程序配置和Portlet.xml
Struts.xml文件是基于XML的文件,Apache Struts框架使用该文件来连接您所开发的不同组件。
您的<s:form 中提到的动作与Struts-action的连线必须定义为struts.xml文件中的条目。
需要以下Struts配置文件:
struts.xml
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN" "https://struts.apache.org/dtds/struts-2.3.dtd"> <struts> <package name="default" extends="struts-portlet-default" namespace="/employee"> <action name="index"> <result>/WEB-INF/jsp/employee/register.jsp</result> </action> </package> <package name="employee" namespace="/employee" extends="struts-portlet-default"> <action name="register" class="com.theitroad.action.RegisterAction"> <result name="SUCCESS">/WEB-INF/jsp/employee/success.jsp</result> <result name="FAILURE">/WEB-INF/jsp/employee/failure.jsp</result> </action> </package> </struts>
通过使用portlet.xml文件,已将Apache Struts与给定的Portlet容器集成在一起。
在这种情况下,应为此目的使用新的init参数。
跟随使用的Portlet.xml文件。
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 https://java.sun.com/xml/ns/portlet/portlet-app_2_0.xsd"> <portlet> <description>Register Employee</description> <portlet-name>RegisterEmployee</portlet-name> <portlet-class>org.apache.struts2.portlet.dispatcher.Jsr286Dispatcher</portlet-class> <init-param> <name>actionPackages</name> <value>com.theitroad.action</value> </init-param> <!-- The namespace for the actions configured for view mode --> <init-param> <name>viewNamespace</name> <value>/employee</value> </init-param> <!-- The default action to invoke in view mode. --> <init-param> <name>defaultViewAction</name> <value>index</value> </init-param> <supports> <mime-type>text/html</mime-type> <portlet-mode>view</portlet-mode> </supports> <supported-locale>en</supported-locale> <portlet-info> <title>Register Employee</title> <short-title>Register Employee</short-title> <keywords>Employee,Registration</keywords> </portlet-info> </portlet> </portlet-app>
以下是上面列出的Struts和Portlet配置文件的详细说明:
您的Portlet必须是JSR286Dispatcher`类的实例。
我们定义了三个附加参数,actionPackages,viewNamespace和defaultViewAction。
打开包含已部署Portlet的门户页面后,将使用定义的
defaultViewAction
。
由于索引是值,因此应将索引定义为struts.xml文件中的操作。定义的" actionPackages"将用于确定包含Struts-actions类的Java包。
定义的" viewNamespace"将确定为"查看模式"配置的动作的名称空间。
它也适用于为"编辑"和"帮助"模式定义操作。Struts配置文件已定义"注册"操作,一旦用户提交了表单的注册,便会立即使用该操作。
定义的"注册"动作具有两个不同的结果,成功和失败用于确定Struts框架在完成对动作类的execute调用之后使用的下一个视图。
部署描述符
web.xml
<?xml version="1.0" encoding="UTF-8"?> <!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>RegisterEmployee</display-name> <filter> <filter-name>struts2</filter-name> <filter-class> org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter </filter-class> </filter> <filter-mapping> <filter-name>struts2</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> </web-app>
员工DAO和ConnectionUtility
在EmployeeDAO和ConnectionUtility之下,可以帮助您获得数据库连接并在之后创建用户。
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, Integer.parseInt(employee.getId())); query.setString(2, employee.getName()); query.setString(3, employee.getJob()); query.setInt(4, Integer.parseInt(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; } }
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://localhost:3306/theitroad", properties)); } return connection; } public void setConnection(Connection connection) { this.connection = connection; } }