项目经验分享--strust2一个程序员难解难分的队友啊!

队友就是你NB的时候还能让你冷静思考的那货;言归正传

1、放置路径:
Struts2默认的配置文件为struts.xml ,该文件需要存放在项目中的WEB-INF/classes文件下

2、启动方式:采用过滤器的方式启动:

         <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>*.do</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>*.action</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>*.htm</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>*.jsp</url-pattern>
</filter-mapping>

3.具体的注解方式的配置:

<?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>
  <constant name="struts.devMode" value="true" />
  <!-- 约定Action类执行完毕以后返回资源的结果路径,必须以 "/" 开头 -->
  <constant name="struts.convention.result.path" value="/main,/members" /> 
  <!-- 这个属性指定的是Strtus.xml中配置的 <package>节点的父节点 -->
  <!-- <constant name="struts.convention.default.parent.package" value="admin-default" /> -->
  <!-- 确定搜索包的路径。只要是结尾为action的包都要搜索 -->
  <constant name="struts.convention.package.locators" value="action" />
  <!-- 约定Action 类的项目根包 :值得注意的命名空间-->
  <constant name="struts.convention.package.locators.basePackage" value="com.san.console.action" />
  <package name="admin-default" extends="convention-default">
<interceptors>
   <!--权限拦截器-->
   <interceptor name="permissionInterceptor" class="com.san.console.interceptor.PermissionInterceptor" />
   <interceptor-stack name="permitStack">
           <interceptor-ref name="permissionInterceptor"/>
              <interceptor-ref name="actionMappingParams"/>
              <interceptor-ref name="params">
                  <param name="excludeParams">dojo\..*,^struts\..*</param>
              </interceptor-ref>
              <interceptor-ref name="conversionError"/>
              <!-- 一定要加上默认的拦截器 如果不写会被覆盖的   -->
              <interceptor-ref name="defaultStack"/>
       </interceptor-stack>
   </interceptors>
   <!-- 配置struts2框架运行时,默认执行自定义拦截器栈 -->
   <default-interceptor-ref name="permitStack" />
   <!-- 全局返回值 -->
<global-results>
      <!-- 登录页 -->
      <result name="loginpage" type="redirect">/login.jsp</result>
      <!-- 无权提示页 -->
          <result name="nopermit" type="redirect">/main/common/nopermit.jsp</result>
          <!-- 异常错误页 -->
          <result name="allException">/main/common/error.jsp</result>
    </global-results> 
<global-exception-mappings>
<exception-mapping result="allException" exception="java.lang.Exception" />
</global-exception-mappings> 
</package> 
</struts>


解释几点概念吧
<constant name="struts.convention.result.path" value="/main,/members" /> 
就是struts2返回页面的结果(页面)的结合。就是说返回页面也在main,或者members这两个文件夹下面;


还有一个权限拦截器:(在未来的某篇博客中我会重点解释下sessionId这个穿越APP和服务端的好东西)

public class PermissionInterceptor extends AbstractInterceptor {
	public String intercept(ActionInvocation invocation) throws Exception {
		Object action = invocation.getAction();
		String classType = action.getClass().getName();
		Class className = Class.forName(classType);		
		Method method = action.getClass().getMethods()[0];
		String res = "";
		String reqActionName = invocation.getProxy().getActionName();
		String actionname = invocation.getProxy().getActionName();
		String methodname = invocation.getProxy().getMethod();
		ApplicationContext ctx = WebApplicationContextUtils.getRequiredWebApplicationContext(ServletActionContext.getServletContext());	
		String actionDesc = LocalizedTextUtil.findDefaultText(className.getSimpleName()+"."+methodname, new Locale(ApplicationConfig.DEFAULT_LOCALE));
		LogRecord logRecord = method.getAnnotation(LogRecord.class);
		if (!StringUtils.isNotBlank(actionDesc) && logRecord != null) {
			actionDesc = logRecord.actionDesc();
		}
		if (action instanceof Protected) {
			Protected pro = (Protected) action;
			if (!pro.hasPermission(actionname, methodname)) {
				//return "nopermission";注释掉,先不使用
			}
			if(StringUtils.equals(actionname, "systemlogin") && StringUtils.equals(methodname, "login")){//跳过登陆action
				return invocation.invoke();
			}else{
				//根据session获取用户相关的权限
				ManageUser gmacUser = (ManageUser) Struts2Utils.getSession().getAttribute(WebConstant.SESSION_EMPLOYEE_BEAN);
				if(gmacUser==null){
					return "loginpage";
				}
		 }
		}
		return invocation.invoke();
	}
}


注意:拦截器在session中会找一次用户。如果发现没有的话。就会退出到登录页面
//根据session获取用户相关的权限
ManageUser gmacUser = (ManageUser) Struts2Utils.getSession().getAttribute(WebConstant.SESSION_EMPLOYEE_BEAN);
if(gmacUser==null){
return "loginpage";
}
这里就必须提一下strust2的标签了:global-results、具有全局属性、
<global-results>
    <result name="loginpage" type="redirect">/index2.jsp</result>
          <result name="nopermit" type="redirect">/main/common/nopermit.jsp</result>
          <result name="allException">/main/common/error.jsp</result>
</global-results>

4、最少依赖JAR包:

struts2-core-2.x.x.jar :Struts 2框架的核心类库
xwork-core-2.x.x.jar :XWork类库,Struts 2在其上构建
ognl-2.6.x.jar :对象图导航语言(Object Graph Navigation Language),struts2框架通过其读写对象的属性
freemarker-2.3.x.jar :Struts 2的UI标签的模板使用FreeMarker编写
commons-logging-1.x.x.jar :ASF出品的日志包,Struts 2框架使用这个日志包来支持Log4J和JDK 1.4+的日志记录。
commons-fileupload-1.2.1.jar 文件上传组件,2.1.6版本后必须加入此文件;


5、案例分析
登录案例,只做路径和配置方面的介绍
5.1 登录页面:

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@include file="/main/common/taglibs.jsp"%> 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
  <head>
    <title>${ APP_NAME}</title>
    <%@include file="/main/common/meta.jsp"%>
    <link href="${ctx }/css/login.css" rel="stylesheet" type="text/css" />
    <script type="text/javascript" src="${ctx }/js/plugin/jquery.cookie.js"></script>
    <!-- 引用登录的js -->
    <script type="text/javascript" src="${ctx }/js/login.js"></script>
  </head>
  <body>
    <form action="#" method="post" name="loginForm">
    <dl>
		<dd>
	      <table border="0" cellpadding="4" cellspacing="0">
			  <tr>
			    <td><div id="loading" style="position:absolute; text-align:center; display: none;"><img src="images/ajax-loader.gif" alt="登录中……" /> </div></td>
			    <td colspan="2"><div id="msg" class="red" style="height:15px;"></div></td>
			  </tr>
			  <tr>
			    <td align="right" width="40">用户名</td>
			    <td align="left" width="198"><input name="userName" type="text" class="input_bg" id="name" /></td>
			    <td rowspan="2" align="left"><img src="images/login_button.jpg" width="62" height="62" style="cursor: pointer;" onClick="javascript:login();"/></td>
			  </tr>
			  <tr>
			    <td align="right">密 码</td>
			    <td align="left"><input name="password" type="password" class="input_bg" id="pwd" /></td>
			  </tr>
			  <tr>
			    <td> </td>
			    <td align="left" valign="top"><input type="checkbox" name="rememberloginname" id="rememberloginname" />
			    记住用户名</td>
			    <td> </td>
			  </tr>
			</table>
	    </dd>
		</dl>
	</form>
  </body>
</html>
<script type="text/javascript">
//get cookie name
if($.cookie('loginname')!=null){
	$("#name").val($.cookie('loginname'));
	$("#rememberloginname").attr("checked",true);
}
</script>

5.2 login.js

// JavaScript Document
if (self != top) 
{
  parent.location.href = webroot+"index.jsp";
}
function showMsg(msg)
{
	var obj = document.getElementById("msg");
	obj.innerHTML=msg;
}
function vaildateForm()
{
	var name = document.getElementById("name");
	var pwd = document.getElementById("pwd");
	var v = document.getElementById("vaildate");
	if(name.value=='') {
		showMsg("帐号不能为空!");
		name.focus();
		return false;
    }else if(!(/^[A-Za-z]{1}[A-Za-z0-9\_]+$/.test(name.value) && name.value.length >=5 && name.value.length<=35)){
    	showMsg("帐号必须是由5~35位英文字母或数字组成的字符!");
    	name.focus();
    	return false;
    }
	if(pwd.value=='') {
		showMsg("密码不能为空!");
		pwd.focus();
		return false;
	}
	/*if(!/(?=^.{8,16}$)(?=(?:.*?\d){1})(?=.*[a-z])(?=(?:.*?[A-Z]){1})(?=(?:.*?[!@#$%*()_+^&}{:;?.]){1})(?!.*\s)[0-9a-zA-Z!@#$%*()_+^&]*$/.test(pwd.value)){
		showMsg("密码必须由8~16位大小写字母、数字和特殊字符组成!");
		pwd.focus();
		return false;
	}*/
	return true;
}

function login(){
	if(vaildateForm()){
		//登录跳转
		$.ajax({   
	        type:"POST",   //传值方式
	        url:"manage/systemlogin!login.action",  //请求的路径
	        dataType: "json",
	        data:{username:$("#name").val(),password:$("#pwd").val()},   //数据格式
	        beforeSend:function(){
	        	$("#loading").css('display','block');//加载效果
	        },                
	        success:function(d, textStatus){
	        	if(d.success==true){
	        		if($("#rememberloginname").attr("checked")){//记住用户名
	        			$.cookie('loginname', $("#name").val(),{expires: 7});
	        		}else{
	        			$.cookie('loginname', null);
	        		}
	        		//登录成功,跳转到导航页面
	        		window.location.href = "manage/systemmanage!toIndexPage.action";
	        	}else{
	        		//师表小时
	        		$("#loading").css('display','none');
			    	showMsg(d.message);
	        	}
	        },
	        //错误展示
			error: function (xhttp, textStatus, errorThrown) { 
				$("#loading").css('display','none');
				//showMsg("System error!");
				alert(errorThrown);
			}               
	     }); 
	}
}

function fireFoxHandler(evt){ 
	if(evt.keyCode==13){ 
		login();
	} 
} 

function ieHandler(evt){ 
	if(evt.keyCode==13){ 
		login();
	} 
} 

if(document.addEventListener){//Firefox
    document.addEventListener("keypress",fireFoxHandler, true); 
}else{ 
	  document.attachEvent("onkeypress",ieHandler); 
}
注意strust2的命名空间:url:"manage/systemlogin!login.action"


5.3 strust2后台配置调用

@Namespace("/manage")
@Actions({   
    @Action(value="systemlogin", 
    	results={
    		@Result(name="loginpage", location="/index.jsp", type="redirect")
    	}),   
    @Action(value="systemmanage", 
    	results={
    		@Result(name="main", location="/main/main.jsp"),
    		@Result(name="desktopPage", location="/main/desktop.jsp"),
    	})   
})  
public class LoginAction  extends BaseActionSupport<ManageUser>{
<pre name="code" class="html">@LogRecord(logType="5", actionDesc = "用户登录")
	public void login() {
		String username = null;
		String password = null;
		try{
			username = Struts2Utils.getParameter("username");
			password = Struts2Utils.getParameter("password");
		}catch(Exception e){
			e.printStackTrace();
		}
		boolean loginResult = false;
		String loginMessage = "";
		Des3Util des3Util = new Des3Util(ApplicationConfig.PASSWORD_KEY);
		
		ManageUser gmacUser = userService.findGmacUserByLoginName(username);
		//记录登录日志
		SysOperateLog operateLog = new SysOperateLog();
		operateLog.setLogTime(new Date());
		operateLog.setLogOperate(WebConstant.LOG_OPERATE_SECURITY);
		operateLog.setLogUser(username);
		operateLog.setLogOperateClass(LoginAction.class.getSimpleName());
		operateLog.setLogOperateMethod("login");
		operateLog.setLogOperateActionName("systemlogin_login");
		if(gmacUser==null){//用户不存在,记录不存在用户尝试登录日志
			loginMessage = "用户不存在";
//			loginMessage = LocalizedTextUtil.findDefaultText("tips.login.noexist", new Locale(ApplicationConfig.DEFAULT_LOCALE));
			//记录无效用户名登录尝试记录日志
			operateLog.setLogOperateResult(WebConstant.OPERATE_FAIL);//操作失败
//			operateLog.setLogContent(MessageFormat.format(LocalizedTextUtil.findDefaultText("tips.login.fail", new Locale(ApplicationConfig.DEFAULT_LOCALE)),Struts2Utils.getRequest().getRemoteAddr())+loginMessage);
		}else {//用户存在,也记录登录日志
				String enCodePassward = des3Util.getEncString(password);//加密后匹配
					if(userService.userLogin(username, enCodePassward)==true){//验证初始密码
						loginResult = true;
					}else{//密码错误
						loginMessage = "密码错误";
//						loginMessage = LocalizedTextUtil.findDefaultText("tips.login.passwrong", new Locale(ApplicationConfig.DEFAULT_LOCALE));
					}
			if(loginResult){//验证成功,进行登录操作并存储用户信息到session,存储最近登录信息
				gmacUser.setLastIp(gmacUser.getLoginIp());
				gmacUser.setLastTime(gmacUser.getLoginTime()==null?(new Date()):gmacUser.getLoginTime());//2012.03.05修改用户未过期禁用bug
				gmacUser.setLoginFails(0);
				gmacUser.setLoginTime(new Date());
				gmacUser.setLoginIp(Struts2Utils.getRequest().getRemoteAddr());
				List list = userService.findRootSysMenuListByUserId(gmacUser.getId());
				if((list==null || list.size()<1) && !ApplicationConfig.getSupperUserList().contains(gmacUser.getUserLoginName())){
					loginResult = false;
					operateLog.setLogOperateResult(WebConstant.OPERATE_FAIL);//操作失败
				}else{
					Struts2Utils.getSession().setAttribute(WebConstant.SESSION_EMPLOYEE_BEAN, gmacUser);
					//设置用户可用的action name属性
					ServletContext sctx = Struts2Utils.getSession().getServletContext();
					String accesslist = "systemmanage_openDeskTopPage,systemmanage_toIndexPage,account_openChangePwdPage,systemlogin_logout,account_getUserPrivateMenuList,account_changePwd,ira_getUploadStatusBar4Br4";
					sctx.setAttribute(WebConstant.ACCESS_ACTIONLIST, accesslist);
					operateLog.setLogOperateResult(WebConstant.OPERATE_SUCCESS);//操作成功
				}
			}else{//登录失败
				gmacUser.setLoginFails(1);
				gmacUser.setLoginTime(new Date());
				gmacUser.setLoginIp(Struts2Utils.getRequest().getRemoteAddr());
				if(!StringUtils.isNotBlank(loginMessage)){
					loginMessage = LocalizedTextUtil.findDefaultText("tips.login.systemerror", new Locale(ApplicationConfig.DEFAULT_LOCALE));
				}
				operateLog.setLogOperateResult(WebConstant.OPERATE_FAIL);//操作失败
//				operateLog.setLogContent(MessageFormat.format(LocalizedTextUtil.findDefaultText("tips.login.fail", new Locale(ApplicationConfig.DEFAULT_LOCALE)),gmacUser.getLoginIp())+loginMessage);
			}
			userService.modifyAccount(gmacUser);
		}
		operateLog.setIsAuthed(true);
		operateLog.setLogType(WebConstant.LOG_ENVENT_TYPE6);
		operateLogService.writeOperateLog(operateLog);
		
		
		Struts2Utils.renderJson("{\"success\":"+loginResult+",\"message\":\""+loginMessage+"\"}");
	}

这里为什么要返回的json字符串。理由是ajax请求要拿到返回值解析啊!


找一个相对比较正规的解析:
add信息(js中的部分内容):
case 'add':
openDialog(webroot+'san/cusInfo!cusInfoAddPage.action'+'?channel_no='+channel_no,700,150);
break;


后台action:Namespace和action和URL:san/cusInfo!对应;
@Namespace("/san")
@Actions({   
    @Action(value="cusInfo",
        results={
//返回值和对应页面路径
    @Result(name="cusInfoAddPage", location="/main/san/cusinfo_add.jsp"),
    @Result(name="channelCusInfoAddPage", location="/main/san/channelcusInfo_add.jsp")
    })
}) 


/***
* 打开新增页面的方法
*/
public String cusInfoAddPage(){
String channel_no = Struts2Utils.getParameter("channel_no");
if(StringUtils.isNotBlank(channel_no)){
Struts2Utils.getRequest().setAttribute("channel_no", channel_no);
}
return "cusInfoAddPage";
}


以上完整Ok







你可能感兴趣的:(拦截器,strust2标签)