前面《Maven搭建SSH框架》教程中分别基于 Spring 和 Hibernate 实现了 Service 接口和 DAO 接口功能,接下来基于 Struts2实现 Web 层功能。
根据前面的 Jsp/Servlet 实现,对需求的理解和 Struts2 开发的相关组件的了解(Struts2 需要单独参考其他资料),Struts2 Web 层的代码需要做以下工作。
视图层代码同以前用 Jsp/Servlet 开发的内容一样,有两个 jsp。
UserAction.java,实现用户 CRUD 的所有控制逻辑代码。
applicationContext.xml,配置 Spring 容器的初始化组件。
完成 Struts 常量的配置和 Action 的配置。
配置 Struts 的入口过滤器和 Spring 的初始化 Listener。
基于 webapp 的 Archetypes 创建 Web 工程,这里用的是 webapp-javaee6,如图 1 所示。
图 1 选择 webapp-javaee6 创建 Web 应用
单击 Next 按钮,在输入框中输入对应信息,单击 Finish 按钮,创建一个 Maven 的 Web 工程,仓库目录结构如图 2 所示。
图 2 Struts Web工程结构
pom.xml 内容如下:
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>cn.com.mvn.pom</groupId>
<artifactId>StrutsPOM</artifactId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<groupId>cn.com.mvn.ssh.demo</groupId>
<artifactId>MvnSSHDemo.Struts</artifactId>
<packaging>war</packaging>
<name>MvnSSHDemo.Struts</name>
<url>http://maven.apache.org</url>
<dependencies>
<!-- struts json插件 -->
<!-- https://mvnrepository.com/artifact/org.apache.struts/struts2-json-plugin -->
<dependency>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-json-plugin</artifactId>
<version>2.3.28</version>
</dependency>
<dependency>
<groupId>cn.com.mvn.ssh.demo.dao.hibernate</groupId>
<artifactId>MvnSSHDemo.DAO.Hibernate</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>cn.com.mvn.ssh.demo</groupId>
<artifactId>MvnSSHDemo.Service</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>cn.com.mvn.ssh.demo</groupId>
<artifactId>MvnSSHDemo.Service.impl</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
<build>
<plugins>
<!-- <plugin> <groupId>org.mortbay.jetty</groupId> <artifactId>maven-jetty-plugin</artifactId>
<version>6.1.26</version> <configuration> <webAppSourceDirectory>${basedir}/src/main/webapp</webAppSourceDirectory>
</configuration> </plugin> -->
<plugin>
<!-- 指定插件名称及版本号 -->
<groupId>org.codehaus.cargo</groupId>
<artifactId>cargo-maven2-plugin</artifactId>
<version>1.4.8</version>
<configuration>
<wait>true</wait> <!--是否说明,操作start、stop等后续操作必须等前面操作完成才能继续 -->
<container> <!-- 容器的配置 -->
<containerId>tomcat7x</containerId> <!-- 指定tomcat版本 -->
<type>installed</type> <!-- 指定类型:standalone, installed等 -->
<home>C:\java\servers\apache-tomcat-7.0.69_64</home> <!-- 指定Tomcat的位置,即catalina.home -->
</container>
<configuration> <!-- 具体的配置 -->
<type>existing</type> <!-- 类型,existing:存在 -->
<home>C:\java\servers\apache-tomcat-7.0.69_64</home> <!-- Tomcat的位置,即catalina.home -->
</configuration>
<deployables> <!-- 部署设置 -->
<deployable> <!-- 部署的War包名等 -->
<groupId>cn.com.mvn.ssh.demo</groupId>
<artifactId>MvnSSHDemo.Struts</artifactId>
<type>war</type>
<properties><!-- 部署路径 -->
<context>MvnSSHDemo</context>
</properties>
</deployable>
</deployables>
<deployer> <!-- 部署配置 -->
<type>installed</type> <!-- 类型 -->
</deployer>
</configuration>
<executions>
<!-- 执行的动作 -->
<execution>
<id>verify-deployer</id>
<phase>install</phase> <!-- 解析install -->
<goals>
<goal>deployer-deploy</goal>
</goals>
</execution>
<execution>
<id>clean-deployer</id>
<phase>clean</phase>
<goals>
<goal>deployer-undeploy</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.0.2</version>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
相对以前的工程,这里有如下几点不同。
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>测试用户CRUD操作</title>
<script type="text/javascript" src="js/jquery-3.2.1.min.js"></script>
<script type="text/javascript">
$(document).ready(function() {
// 页面加载完后,自动发searchUsersServlet请求,加载到userListDiv中显示
$("#userListDiv").load("userAction!searchUsers.action");
});
// 新增 按钮事件触发函数
function toAdd() {
// 获取addForm中的请求信息
var _data = $("#addForm").serialize();
//alert(_data);
// 发添加新用户的Ajax请求
$.ajax({
type : 'post',
url : 'userAction!addUser.action',
data : _data,
success : function(msg) {
alert(msg.message);
// 更新最新的用户列表信息
$("#userListDiv").load("userAction!searchUsers.action");
}
});
}
function toEdit() {
var _data = $("#editForm").serialize();
alert(_data);
$.ajax({
type : 'post',
url : 'userAction!editUser.action',
data : _data,
success : function(msg) {
alert(msg.message);
$("#userListDiv").load("userAction!searchUsers.action");
}
});
}
function toDelete() {
var chks = $("input[name='checkbox']:checked");
if (chks.length == 0) {
alert("请选择要删除的用户");
} else if (chks.length > 1) {
alert("一次只能删除一个用户");
} else {
var to = confirm("您确定要删除选中的用户?");
if (to) {
var _data = "id=" + chks.val();
$.ajax({
type : 'post',
data : _data,
url : 'userAction!deleteUser.action',
success : function(msg) {
alert(msg);
$("#userListDiv").load("userAction!searchUsers.action");
}
});
}
}
}
function toShowAdd() {
$("#LayerAdd").show(1000);
}
function toShowEdit() {
//alert($("input[name='checkbox']:checked").length);
var chks = $("input[name='checkbox']:checked");
if (chks.length == 0) {
alert("请选择要编辑的用户");
} else if (chks.length > 1) {
alert("一次只能修改一个用户");
} else {
var _data = "id=" + chks.val();
$.ajax({
type : 'post',
data : _data,
url : 'userAction!searchUser.action?type=byId',
dataType : 'json',
success : function(msg) {
$("#editForm #id").val(msg.urId);
$("#editForm #userName").val(msg.urUserName);
$("#editForm #age").val(msg.urAge);
$("#editForm #status").val(msg.urStatus);
//alert($("#editForm #age").val());
$("#LayerEdit").show(1000);
}
});
}
}
function toCloseAdd() {
$("#LayerAdd").hide(1000);
}
function toCloseEdit() {
$("#LayerEdit").hide(1000);
}
</script>
<style type="text/css">
<!--
.STYLE2 {
color: #000000
}
#LayerAdd {
position: absolute;
left: 113px;
top: 183px;
width: 434px;
height: 193px;
z-index: 1;
background-color: #99FFFF;
display: none;
}
#LayerEdit {
position: absolute;
left: 113px;
top: 183px;
width: 434px;
height: 193px;
z-index: 1;
background-color: #99FFFF;
display: none;
}
-->
</style>
</head>
<body>
<div id="LayerAdd">
<form name="addForm" name="addForm" id="addForm" method="post" action="">
<table width="98%" border="0" align="center" cellpadding="0" cellspacing="0">
<tr>
<td colspan="2" align="center">
<strong><BR>添加新用户<br></strong>
</td>
</tr>
<tr>
<td width="47%" align="right">用户名:</td>
<td width="53%">
<input name="user.urUserName" type="text" id="userName">
</td>
</tr>
<tr>
<td align="right">密码:</td>
<td>
<input name="user.urPassword" type="password" id="password">
</td>
</tr>
<tr>
<td align="right">年龄:</td>
<td>
<input name="user.urAge" type="text" id="age">
</td>
</tr>
<tr>
<td colspan="2"> </td>
</tr>
<tr>
<td colspan="2" align="center">
<input type="button" name="Submit4" value="添加" onclick="toAdd()">
<input type="button" name="Submit5" value="关闭" onclick="toCloseAdd()">
</td>
</tr>
</table>
</form>
</div>
<div id="LayerEdit">
<form name="editForm" id="editForm" method="post" action="">
<input type="hidden" name="id" id="id" />
<table width="98%" border="0" align="center" cellpadding="0" cellspacing="0">
<tr>
<td colspan="2" align="center">
<strong><br>修改用户信息<br></strong>
</td>
</tr>
<tr>
<td width="47%" align="right">用户名:</td>
<td width="53%">
<input name="userName" type="text" id="userName" readonly="readonly">
</td>
</tr>
<tr>
<td align="right">年龄:</td>
<td>
<input name="age" type="text" id="age">
</td>
</tr>
<tr>
<td align="right">状态:</td>
<td>
<select name="status" id="status">
<option value="Active">Active</option>
<option value="Inactive">Inactive</option>
<option value="Locked">Locked</option>
<option value="Deleted">Deleted</option>
</select>
</td>
</tr>
<tr>
<td colspan="2"> </td>
</tr>
<tr>
<td colspan="2" align="center">
<input type="button" name="Submit4" value="修改" onclick="toEdit()">
<input type="button" name="Submit5" value="关闭" onclick="toCloseEdit()">
</td>
</tr>
</table>
</form>
</div>
<p> </p>
<p>测试用户CRUD页面</p>
<table width="539" border="1">
<tr>
<td colspan="5" align="right">
<input type="button" name="Submit" value="新增" onclick="toShowAdd()">
<input type="submit" name="Submit2" value="修改" onclick="toShowEdit()">
<input type="button" name="Submit3" value="删除" onclick="toDelete()">
</td>
</tr>
<tr>
<td>
<div id="userListDiv"></div>
</td>
</tr>
</table>
<p> </p>
</body>
</html>
注:index.jsp 中的 JS 用到了 jQuery,要注意将 jQuery 的 JS 代码添加到应用中,并且用 script 应用到页面。index.jsp 中的添加函数、修改函数和删除函数从后台返回的是用 JSON 封装的提示信息。
① Message.java 代码如下所示:
package cn.com.mvn.ssh.demo.web.vo;
public class Message {
private String code;
private String message;
public Message(String message) {
super();
this.message = message;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
UserAction.java
package cn.com.mvn.ssh.demo.web.action;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;
import cn.com.mvn.ssh.demo.entity.MvnUser;
import cn.com.mvn.ssh.demo.service.IUserService;
import cn.com.mvn.ssh.demo.web.vo.Message;
@Controller("userAction")
public class UserAction {
@Autowired
@Qualifier("userService")
private IUserService userService;
private MvnUser user;
private int id;
private String userName;
private String type;
private String status;
private int age;
private Message message;
// 新增用户的执行方法
public String addUser() {
String result = "addSuccess";
message = new Message("添加成功");
try {
// 调用service,创建用户
userService.createUser(user);
} catch (Exception e) {
e.printStackTrace();
message.setMessage("添加失败:" + e.getMessage());
}
return result;
}
// 删除用户的执行方法
public String deleteUser() {
String result = "deleteSuccess";
message = new Message("删除成功");
try {
userService.deleteUser(id);
} catch (Exception e) {
e.printStackTrace();
message.setMessage("删除失败:" + e.getMessage());
}
return result;
}
// 修改用户的执行方法
public String editUser() {
String result = "editSuccess";
this.message = new Message("修改成功!");
try {
userService.editUser(age, status, id);
} catch (Exception e) {
e.printStackTrace();
message.setMessage("修改失败:" + e.getMessage());
}
return result;
}
// 根据id或用户名查找单个用户的执行方法
public String searchUser() {
String result = "searchUserSeuccess";
if ("byId".equals(type)) {
user = this.userService.searchUser(id);
} else {
user = this.userService.searchUser(userName);
}
return result;
}
private List<MvnUser> userList;
// 查询所有用户列表的执行方法
public String searchUsers() {
String result = "searchUsersSuccess";
this.userList = this.userService.searchUsers();
return result;
}
public List<MvnUser> getUserList() {
return userList;
}
public void setUserList(List<MvnUser> userList) {
this.userList = userList;
}
public MvnUser getUser() {
return user;
}
public void setUser(MvnUser user) {
this.user = user;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Message getMessage() {
return message;
}
public void setMessage(Message message) {
this.message = message;
}
}
3)applicationContext.xml。
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.0.xsd">
<context:component-scan
base-package="cn.com.mvn.ssh.demo" />
</beans>
4)struts.xml。
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.1//EN" "http://struts.apache.org/dtds/struts-2.1.dtd">
<struts>
<include file="struts-default.xml"></include>
<include file="struts-plugin.xml"></include>
<!-- 从Spring容器中获取Action对象 -->
<constant name="struts.objectFactory" value="spring"></constant>
<!-- 请求和Action方法的动态对应 -->
<constant name="struts.enable.DynamicMethodInvocation"
value="true" />
<package name="t" namespace="/" extends="json-default">
<action name="userAction" class="userAction">
<result name="searchUsersSuccess">/userList.jsp</result>
<result name="searchUserSeuccess" type="json">
<param name="root">user</param>
</result>
<result name="editSuccess" type="json">
<param name="root">message</param>
</result>
<result name="deleteSuccess" type="json">
<param name="root">message</param>
</result>
<result name="addSuccess" type="json">
<param name="root">message</param>
</result>
</action>
</package>
</struts>
5)web.xml。
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<display-name>MvnSSHDemo.Struts</display-name>
<!-- 启动Spring 容器 -->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/classes/applicationContext.xml</param-value>
</context-param>
<!-- struts2的总入口过滤器 -->
<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>
<session-config>
<session-timeout>
30
</session-timeout>
</session-config>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
右击“工程”,选择 Run As→Maven install 命令。
Maven 会自动编译、测试代码,并且打成 war 包,将 war 包发布到指定的 Web 服务器的发布目录。接着就可以启动 Tomcat 服务器用浏览器进行测试了。浏览器操作过程同前面基于 Jsp/Servlet 开发的 Demo 一样。
按前面的操作,用户已经独立地实现了各自模块的功能,并且能将各自的功能封装成构件安装到本地仓库、发布到公司搭建的私服上面,供需要的地方当依赖构件使用。
这体现了模块化的思想,同时考虑到框架的依赖配置的共性,用户可以独立创建工程(POM),将每个独立框架的依赖配置都在公共 POM 工程中设置好。
其他要使用的工程只需继承它们就行了,不需要重复配置。比如,MvnSSHDemo.Struts 就是继承自 StrutsPOM。这体现了 Maven 开发过程中的继承运用思想。
但是,当测试 MvnSSHDemo.Struts 模块功能的时候,发现前面的依赖模块的实现需要修改,这时候就要对修改的模块工程进行独立的编译、测试、打包、安装和发布,然后再测试 MvnSSHDemo.Struts。
如果依赖的第三方模块很多,这样每次改动都需要对每个模块进行重复操作,很麻烦。
为了解决这个问题,Maven 里面有个“聚合”的概念。它能将一个个依赖的模块聚合成一个大项目(工程)。
下面创建一个项目,将 MvnSSHDemo 的相关模块都聚合到一起,同时操作,具体步骤如下。
聚合工程结构如图 3 所示。
图 3 聚合工程结构
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>cn.com.mvn.ssh.demo</groupId>
<artifactId>MvnSSHDemo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>pom</packaging>
<name>MvnSSHDemo</name>
<url>http://maven.apache.org</url>
<modules>
<module>../MvnSSHDemo.DAO</module>
<module>../MvnSSHDemo.DAO.Hibernate</module>
<module>../MvnSSHDemo.Service</module>
<module>../MvnSSHDemo.Service.impl</module>
<module>../MvnSSHDemo.Struts</module>
</modules>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
</dependencies>
<build>
<plugins>
</plugins>
</build>
<distributionManagement>
<repository>
<id>archivaServer</id>
<url>http://localhost:8080/repository/internal</url>
</repository>
<snapshotRepository>
<id>archivaServer</id>
<url>http://localhost:8080/repository/snapshots</url>
</snapshotRepository>
</distributionManagement>
</project>
注:这个 pom.xml 中没有太多信息,注意第 13、15、17 和 19 行的配置,就是将相关的依赖工程以模块的形式聚合进来。
这些工程都需要在同一个工作空间下,才能用“../”类似的相对路径进行定位应用。
要对所有模块进行编译、测试、安装、发布的话,都可以直接右击 MvnSSHDemo 工程,选择 Run As→Maven clean→test→install→build.→build 等命令。
当选择 Maven install 命令后,Maven 会自动把整个工程打成 MvnSSHDemo.war 包,发布到 Tomcat 的 webapps 目录中。
同样,如果选择 Maven build… 命令,输入 deploy,单击 Run 按钮,在安装的 Archiva 私服上就可以浏览到所有的构件。
启动 Tomcat,就可以开始测试操作了,只是请注意:前面有搭建 Archiva 私服的,如果这个私服在开发的时候启动着,并且私服就搭建在自己的计算机上,请将它关闭后再启动测试应用的 Tomcat,或者修改测试应用 Tomcat 的端口,否则会出现端口冲突异常。因为 Archiva 也用 Tomcat 服务器,默认端口就是 8080 系列的。
至此,我们在 Maven 上面基于 SSH 完成了一个用户的 CRUD 功能,中间还体现了项目的模块思想、面向接口编程思想和 Maven 的继承、聚合思想。