【允许转载!但请注明出处!】
近日闲来无事研究了一下Struts2,并尝试将其与Spring和Ext整合在了一起。整合的时候遇到了不少麻烦,经过一顿折腾,终于成功完成了下面这个简单的小例子。
新建一个WEB项目,将Struts2的相应jar包添加到web-inf下的lib目录中。我用到的jar包包括antlr-2.7.2.jar、commons-fileupload-1.2.1.jar、commons-logging-1.0.4.jar、freemarker-2.3.15.jar、ognl-2.7.3.jar、struts2-core-2.1.8.jar和xwork-core-2.1.6.jar。因为要与Spring进行整合,所以将struts2-spring-plugin-2.1.8.jar及spring.jar也一并添加进去。然后添加对Spring的支持。本例子使用了ibatis操作Oracle数据库,需要导入ojdbc14.jar、ibatis-2.3.4.726.jar及两个Apach的jar:commons-dbcp.jar、commons-pool.jar。使用json数据返回ext前台需要添加struts2-json-plugin-2.1.8.jar的支持。
修改web.xml的配置:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4"
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<display-name>Struts 2.0 Hello World</display-name>
<!-- 定义Struts 2的FilterDispatcher的Filter -->
<filter>
<filter-name>struts2</filter-name>
<filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
</filter>
<!-- FilterDispatcher用来初始化Struts 2并且处理所有的Web请求 -->
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
<!-- 指定spring配置文件 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/applicationContext.xml,
/WEB-INF/*service.xml,
/WEB-INF/dao/*dao.xml
</param-value>
</context-param>
</web-app>
在WEB-INF下添加Service.xml:
<?xml version="1.0" encoding="GBK"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">
<bean id="loginService" class="service.LoginServiceImpl">
<!-- <property name="loginDao" ref="loginDao"></property> -->
</bean>
<bean id="helloWorldService" class="service.HelloWorldServiceImpl">
<property name="loginDao" ref="loginDao"></property>
</bean>
</beans>
在WEB-INF下新建dao文件夹,并在dao下添加dao.xml和sql-map-config.xml
dao.xml文件如下:
<?xml version="1.0" encoding="GBK"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd">
<bean id="abstractDao" abstract="true">
<property name="sqlMapClient" ref="sqlMapClient"/>
</bean>
<bean id="loginDao" class="dao.LoginDao" parent="abstractDao"></bean>
</beans>
sql-map-config.xml文件如下:
<?xml version="1.0" encoding="GBK" ?>
<!DOCTYPE sqlMapConfig
PUBLIC "-//ibatis.apache.org//DTD SQL Map Config 2.0//EN"
"http://ibatis.apache.org/dtd/sql-map-config-2.dtd">
<sqlMapConfig>
<settings lazyLoadingEnabled="true" useStatementNamespaces="true" />
<sqlMap resource="dao/maps/TB_USER_SqlMap.xml"/>
</sqlMapConfig>
修改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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<description>加载属性文件列表</description>
<property name="locations">
<list>
<value>WEB-INF/jdbc.properties</value>
</list>
</property>
</bean>
<!-- 需导入commons-dbcp.jar、commons-pool.jar和连接数据库的包 -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<bean id="sqlMapClient" class="org.springframework.orm.ibatis.SqlMapClientFactoryBean">
<description>加载ibatis</description>
<property name="configLocation" value="WEB-INF/dao/sql-map-config.xml"></property>
<property name="dataSource" ref="dataSource"></property>
</bean>
<bean id="HelloWorldAction" class="tutorial.HelloWorld" >
<property name="helloWorldService">
<ref bean="helloWorldService"/>
</property>
</bean>
在WEB-INF下添加jdbc.properties文件
jdbc.driverClassName=oracle.jdbc.driver.OracleDriver
jdbc.url=jdbc:oracle:thin:ljlei/ljlei@localhost:1521:orcl
jdbc.username=ljlei
jdbc.password=ljlei
在src下添加struts2的配置文件 struts.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">
<struts>
<!-- 指定Web应用的默认编码集,相当于调用HttpServletRequest的setCharacterEncoding方法 -->
<constant name="struts.i18n.encoding" value="UTF-8" />
<include file="struts-default.xml" />
<!-- Struts 2的Action必须放在指定的包空间下定义 -->
<!-- <package name="tutorial" extends="struts-default"> -->
<package name="tutorial" namespace="/" extends="json-default">
<interceptors>
<interceptor name ="auth" class ="tutorial.AuthorizationInterceptor" />
</interceptors>
<action name="HelloWorld" class="HelloWorldAction">
<result type="json" />
<!--
<result name="login">SayHello.jsp</result>
<result name="error">errorPage.jsp</result>
<result name="success">HelloWorld.jsp</result>
-->
</action>
</package>
</struts>
配置文件完成后,添加相应的java类文件
在src下新建HelloWorld.java
package tutorial;
import java.text.DateFormat;
import java.util.Date;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.apache.struts2.ServletActionContext;
import service.HelloWorldService;
import com.opensymphony.xwork2.ActionContext;
import com.opensymphony.xwork2.ActionSupport;
import domain.User;
public class HelloWorld extends ActionSupport {
private User user;
private String message;
private boolean success;
private HelloWorldService helloWorldService;
public boolean isSuccess() {
return success;
}
public void setSuccess(boolean success) {
this.success = success;
}
public HelloWorldService getHelloWorldService() {
return helloWorldService;
}
public void setHelloWorldService(HelloWorldService helloWorldService) {
this.helloWorldService = helloWorldService;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
@Override
public String execute() throws Exception{
System.out.println(user.getUsername()+"---"+user.getPassword());
HttpServletRequest request = ServletActionContext.getRequest();
HttpServletResponse response = ServletActionContext.getResponse();
response.setContentType("text/html;charset=utf-8");
if(helloWorldService.check(user)){
String jsonString = "{success:true,msg:'验证成功!'}";
System.out.println(jsonString);
response.getWriter().print(jsonString);
return null;
}else {
String jsonString = "{success:false,errors:'账户密码验证失败'}";
System.out.println(jsonString);
response.getWriter().print(jsonString);
return null;
}
}
public String aliasAction(){
message = "自定义Action调用方法";
return SUCCESS;
}
}
在src下新建HelloWorldService.java和HelloWorldServiceImpl.java
package service;
import domain.User;
public interface HelloWorldService {
public boolean check(User user);
}
package service;
import tutorial.StringUtil;
import dao.LoginDao;
import domain.User;
public class HelloWorldServiceImpl implements HelloWorldService {
private LoginDao loginDao;
public LoginDao getLoginDao() {
return loginDao;
}
public void setLoginDao(LoginDao loginDao) {
this.loginDao = loginDao;
}
public boolean check(User user) {
System.out.println("==== HelloWorldServiceImp ====");
System.out.println(user.getUsername()+user.getPassword());
User user2 = loginDao.checkUser(user);
if(null == user2){
System.out.println("没有该用户");
return false;
}else {
String encodePassword = StringUtil.MD5Encode(user.getPassword());
System.out.println(encodePassword);
if(user2.getPassword().equals(encodePassword)){
return true;
}else {
System.out.println("密码错误");
return false;
}
}
}
}
在src下添加domain包,并添加User实体类
package domain;
public class User {
private String username;
private String password;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
在src下添加dao包,新建LoginDao.java
package dao;
import org.springframework.dao.DataAccessException;
import org.springframework.orm.ibatis.support.SqlMapClientDaoSupport;
import domain.User;
public class LoginDao extends SqlMapClientDaoSupport {
public User checkUser(User user) throws DataAccessException{
System.out.println("====== LoginDao ======");
System.out.println(user.getUsername()+user.getPassword());
return (User)this.getSqlMapClientTemplate().queryForObject("TB_USER.selectUserByName",user);
}
}
在dao包下添加map包,并新建TB_USER_SqlMap.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE sqlMap PUBLIC "-//ibatis.apache.org//DTD SQL Map 2.0//EN" "http://ibatis.apache.org/dtd/sql-map-2.dtd" >
<sqlMap namespace="TB_USER" >
<typeAlias alias="User" type="domain.User" />
<select id="selectUserByName" resultClass="User" parameterClass="User" >
select USERNAME, PASSWORD from TB_USER_INFO where USERNAME = #username:VARCHAR#
</select>
</sqlMap>
在tutorial包下面添加StringUtil.java 用于密码MD5加密
package tutorial;
import java.security.MessageDigest;
public class StringUtil {
private final static String[] hexDigits = {"0", "1", "2", "3", "4", "5",
"6", "7", "8", "9", "a", "b", "c", "d", "e", "f"};
/**
* 转换字节数组为16进制字串
*
* @param b
* 字节数组
* @return 16进制字串
*/
public static String byteArrayToHexString(byte[] b) {
StringBuffer resultSb = new StringBuffer();
for (int i = 0; i < b.length; i++) {
resultSb.append(byteToHexString(b[i]));
}
return resultSb.toString();
}
private static String byteToHexString(byte b) {
int n = b;
if (n < 0)
n = 256 + n;
int d1 = n / 16;
int d2 = n % 16;
return hexDigits[d1] + hexDigits[d2];
}
public static String MD5Encode(String origin) {
String resultString = null;
try {
resultString = new String(origin);
MessageDigest md = MessageDigest.getInstance("MD5");
resultString = byteArrayToHexString(md.digest(resultString
.getBytes()));
} catch (Exception ex) {
}
return resultString;
}
}
最后添加前台EXT页面
在WEBROOT下新建view文件夹,将ext包导入该文件夹下,添加ext的支持。
新建extpage文件夹,在该文件夹下建立login.html和login.js
login.html文件如下:
<html>
<head>
<title>login.html</title>
<link rel="stylesheet" type="text/css" href="../ext/resources/css/ext-all.css" />
<script type="text/javascript" src="../ext/adapter/ext/ext-base.js"></script>
<script type="text/javascript" src="../ext/ext-all.js"></script>
<script type="text/javascript" src="login.js"></script>
</head>
<body>
</body>
</html>
login.js文件如下:
Ext.onReady(function(){
var credentialPrintForm = new Ext.form.FormPanel({
id: 'credentialPrintForm',
border: false,
autoHeight:true,
autoWidth:true,
layout: 'form',
style: 'padding-left:2px;padding-top:2px;padding-right:2px',
labelWidth: 85,
labelAlign:'right',
frame: true,
items: [{
xtype: 'fieldset',
border:false,
layout: 'form',
autoHeight: true,
autoWidth:true,
items: [
{
xtype: 'textfield',
fieldLabel:'用户名',
width: 150,
name:'user.username'
},{
xtype: 'textfield',
inputType: 'password',
fieldLabel:'密码',
width: 150,
name:'user.password'
}]
}]
});
var credentialPrint_oRevertWindow = new Ext.Window({
id: '',
title: '系统登录',
width: 325,
height: 162,
modal: true,
draggable:false, //禁止拖动
resizable: false, //禁止改变大小
constrainHeader: true,
closable:false,
items: [credentialPrintForm],
buttons: [{
text:'登录',
tooltip:'登录',
handler:function(){
credentialPrintForm.getForm().submit({
waitTitle:'消息',
waitMsg :'请求提交中,请稍后...',
url:'HelloWorld.action',
method:'POST',
success:function(fundBuy_form,action){
var record = action.result.data;
Ext.Msg.alert('消息',action.result.msg);
document.location='../../HelloWorld.jsp';
},
failure : function(fundBuy_form, action) {
if(action.failureType == Ext.form.Action.SERVER_INVALID){
Ext.Msg.alert('错误',action.result.errors);
}else if(action.failureType == Ext.form.Action.CONNECT_FAILURE){
Ext.Msg.alert('错误','网络连接错误,请稍后再试!');
}else{
Ext.Msg.alert('错误','请求后台出错!');
}
}
});
}
}, {
text: '重置',
tooltip: '重置',
handler: function(){
credentialPrintForm.getForm().reset();
}
}]
});
credentialPrint_oRevertWindow.show();
})
以上就是整个例子,在测试过程中,遇到一个"here is no Action mapped for action name HelloWorld"错误,查看网上有几种解决方案:
1) 查看struts配置文档中配置的action名称,是否与表单提交中action相同
2) 查看result是否正确,注意type=""中的值
3)将struts.xml放到src下
仔细看过我的程序似乎都不存在这些问题,折腾了半天,原来是struts2-json-plugin-2.1.8.jar没有导入。晕死。。