Web常使用的功能经验笔记第1季
刘岩
Email:suhuanzheng7784877@163.com
- 前言
Apache的Struts2已经是很流行的MVC Web框架了,很多Web开发人员都是使用它做为Web框架。它是在 struts 和WebWork的技术基础上进行了合并,全新的Struts 2框架。其全新的Struts 2的体系结构与Struts 1的体系结构的差别巨大。Struts 2以WebWork为核心,采用拦截器的机制来处理用户的请求,这样的设计也使得业务逻辑控制器能够与Servlet API完全脱离开,所以Struts 2可以理解为WebWork的更新产品。因为Struts 2和Struts 1有着太大的变化,但是相对于WebWork,Struts 2只有很小的变化。像Struts2的常用配置功能笔者就不在说了,在此结合作者的Web相关技术(Struts2、JSTL、EL……)使用经验做个总结,希望与您有个共鸣。
- 判断标签<s:if>
当在request域里面的对象需要判断的时候,可以选用<s:if>,当然Struts2的所有标签都必须在一个Action转向后才能使用的,直接访问一个JSP就使用Struts2的标签,报错。
例如:
<s:if test="%{#session.customer==null}"> <A class=buy-btn href="#" title="登录才能抢购">抢购</A> </s:if> <s:if test="%{#session.customer!=null}"> <A class=buy-btn href="proAction!buyProductBefor.action?products.id=${products.id}" title="登录才能抢购">抢购</A> </s:if> |
- 在页面中访问变量(#、%、$)
OGNL是通常要结合Struts 2的标志一起使用。主要是#、%和$这三个符号的使用。
一般使用JSP内置对象域的变量的时候(application、session、request、parameters)都需要使用Struts标签+#来进行访问,一般用于访问Session里面的变量。
例如:
<s:if test="%{#session.customer!=null}"> |
或者
<s:property value="%{#application.myApplicationAttribute}" /> |
在Struts2标签中访问内置对象的变量的时候前面得用%{}将变量括起来。
如果在Action中被注入的对象在ValueStack域中的时候,在页面中可以直接采用el表达式来访问变量。
例如:
<TD><STRONG class="original">${products.sourcePrice}</STRONG></TD> |
如果变量显示的在Action中直接赋值(set)给了request、session域中后,在页面也可以直接使用el表达式来进行访问,但是这里仅仅只是显示,并不能在Struts2标签中判断、计算等。代码如下。
你好,${session.customer.name}! |
一般Struts2标签要配合OGNL表达式一齐使用,包括一些运算、判断、取子字符串等等。在此引用别人博客(http://www.javaeye.com/problems/51144)上的一段话
“#”主要有三种用途: 名称 作用 例子 #parameters.id[0]作用相当于request.getParameter("id") Request:包含当前HttpServletRequest的属性(attribute)的Map #request.userName相当于request.getAttribute("userName") Session:包含当前HttpSession的属性(attribute)的Map #session.userName相当于session.getAttribute("userName") Application:包含当前应用的ServletContext的属性(attribute)的Map #application.userName相当于application.getAttribute("userName") Attr:用于按request > session > application顺序访问其属性(attribute) #attr.userName相当于按顺序在以上三个范围(scope)内读取userName属性,直到找到为止 2.用于过滤和投影(projecting)集合,如books.{?#this.price<100}; “%”符号的用途是在标志的属性为字符串类型时,计算OGNL表达式的值。 “$”有两个主要的用途,用于在国际化资源文件中,引用OGNL表达式。在Struts 2配置文件中,引用OGNL表达式。 |
- JSTL格式化数字
一般用到整数、小数格式化的时候可以直接用JSTL来处理。
使用jstl的fmt标签可以对页面的值进行格式化、国际化显示等功能。
引入标签:<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt"%>
保留整数,小数后一位永远是0
<fmt:formatNumber value="${(products.nowPrice/products.sourcePrice)*10}" pattern="#.0" />折 </STRONG> |
保留两位小数
<!--保留2位小数点,格式化数字--> <STRONG>£¤<fmt:formatNumber value="${products.sourcePrice-products.nowPrice}" pattern="#.##" minFractionDigits="2" /></STRONG> |
读取资源文件
<fmt:message key="global.add" /> |
- Struts2日期标签格式化日期
代码如下
<TD class=order-num> <s:date name="#orderProductListVar.orders.orderDate" format="yyyy-MM-dd HH:mm:ss" /> </TD> |
显示出来得值就是2011-01-10 21:09:26
- 利用Struts2错误标签显示Action中显示发生的错误
<s:fielderror> <s:param>errorMessage</s:param> </s:fielderror> |
其中errorMessage是Action中错误域中的key。
- 利用Struts2标签得到字符串长度和截取子字符串
<!--判断字符串长度--> <s:if test="%{#productsListVar.productMess.length()>=40}"> <s:property value="#productsListVar.productMess.substring(0,40)" />... </s:if> <s:else> <s:property value="#productsListVar.productMess" /> </s:else> |
- Struts2的JSON插件,让Struts2也REST起来
利用Struts2的json插件——struts2-json-plugin-2.1.8.jar(在Struts-all包中有此插件包)
首先看struts.xml的配置
<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" "http://struts.apache.org/dtds/struts-2.0.dtd"> <struts>
<!-- 配置Struts2应用的编码集 --> <constant name="struts.objectFactory" value="spring" /> <constant name="struts.i18n.encoding" value="UTF-8" /> <constant name="struts.enable.DynamicMethodInvocation" value="true" /> <constant name="struts.devMode" value="false" />
<!--基类包--> <package name="baseAdminJsonackage" extends="json-default" abstract="true">
<global-results>
<!--没有权限--> <result name="hasNoToken" type="redirect"> hasNoToken.jsp </result>
<!--进入页--> <result name="input" type="redirect">input.jsp</result>
<!--错误页面--> <result name="error" type="redirect">error.jsp</result>
<!--ajax返回Json信息--> <result name="successJson" type="json"></result> </global-results>
</package>
<!--后台管理相关--> <package name="administrator" extends="baseAdminJsonackage">
<!--用户管理--> <action name="userAction" class="module.system.action.UserAction"> <result name="success" type="redirect"> /admin/jqgrid.jsp </result> <result name="loginSuccess" type="redirect"> /admin/main.jsp </result> <result name="loginError" type="redirect"> /admin/login.jsp </result> </action>
</package> </struts> |
下面来看UserAction的部分代码:
public class UserAction extends BaseAction {
public List objectList;
@JSON public List getObjectList() { return objectList; } public void setObjectList(List objectList) { this.objectList = objectList; } /** * ------------------------临时测试用 * * @return */ public String listTemp() {
// 总记录数 objectList = uxAdminDao.findAll();
return "successJson"; } } |
上面是返回到”successJson”的结果中,在web前端只要通过任何的http请求到
userAction! listTemp.action,返回的结果中就可以获得objectList变量的json格式字符串。前端如何解析,就是前端的事情了。
- Struts2的拦截器
它一般作为Session建权(建立权限)用,在拦截器中进行session的判断。
引用一段别人的代码
先看拦截器配置
<package name="xxx-default" extends="struts-default"> <interceptors> <interceptor name="loginAuth" class="XXX.LoginAuthInterceptor" /> <interceptor-stack name="completeStackWithLoginAuth"> <interceptor-ref name="loginAuth" /> <interceptor-ref name="defaultStack" /> </interceptor-stack> </interceptors> <default-interceptor-ref name="completeStackWithLoginAuth" /> <global-results> <result name="login">/userLogin/error.jsp</result> <result name="expire">/modifyPW/modifyPW.jsp</result> <result name="forbid">/userLogin/forbid.jsp</result> </global-results> </package> |
之后编辑拦截器类
@SuppressWarnings("serial") public class LoginAuthInterceptor extends AbstractInterceptor { @Override public String intercept(ActionInvocation actionInvocation) throws Exception { // 获得会话中的用户身份字段 Map session = actionInvocation.getInvocationContext().getSession(); String user = (String) session.get(ISysParam.SESSION_USER); if (null == user) { return Action.LOGIN; } else { StringBuffer invokeMtd = new StringBuffer(actionInvocation .getProxy().getNamespace()); invokeMtd.append("/" + actionInvocation.getInvocationContext().getName()); String role = (String) session.get(ISysParam.USER_ROLE); //测试代码 如果是用户名是admin 则不进行权限判断 // if(user.equals(ISysParam.ROLETYPE_ADMIN)){ // return actionInvocation.invoke(); // } /* * 得到该所能操作的名称空间 if(可以访问当前的名称空间){ 跳出拦截器 else{ 转到没有权限的页面 } } */ // if (role.contains(invokeMtd.toString())) { // return actionInvocation.invoke(); // } else { // return "forbid"; // } // if (!user.getUserName().equals(ISysParam.ROLETYPE_ADMIN)) { // // 对非ADMIN用户,检查模块访问权限 // if (!chkPrivilege()) { // log.debug(user.getUserName() + ":" +ISysParam.OPER_CANCEL); // return FORBID; // } // } // return actionInvocation.invoke(); // } return actionInvocation.invoke(); } } } |
之后的流程配置如下
<package name="xxx" namespace="/xxx" extends="xxx-default"> <action name="*" method="{1}" class="XXXAction"> <result name="input">{1}.jsp</result> <result name="error">{1}.jsp</result> <result name="success">{1}.jsp</result> </action> </package> <package name="xxx2" namespace="/xxx2" extends="xxx-default"> <action name="*" method="{1}" class="XXX2Action"> <result name="input">{1}.jsp</result> <result name="error">{1}.jsp</result> <result name="success">{1}.jsp</result> </action> </package> |
自己定义
<package name="myPkg" abstract="true" extends="struts-default"></package>
在这个包下面定义拦截器, 这个包下面定义拦截器栈的引用, 引用defaultStack和你自己定义的拦截器!然后你需要用这个拦截器的包都继承这个包就好了!
- Struts2的防刷新提交机制
在Struts2中解决表单的重复提交感觉还算简单。
token: 在活动中检查合法令牌(token), 防止表单的重复提交;
tokenSession: 同上, 但是在接到非法令牌时将提交的数据保存在session中;
首先在struts.xml中配置Action如下信息
<!-- 评论Action --> <action name="commentsAction" class="action.CommentsAction"> <result name="invalid.token" type="redirect">productAction!list.action </result> <interceptor-ref name="defaultStack"> <param name="workflow.excludeMethods">default</param> </interceptor-ref> <interceptor-ref name="token"> <param name="includeMethods">add,update</param> </interceptor-ref> <result name="listByProductsId">/admin/page/commentsList.jsp</result> <result name="add">/admin/page/commentsAdd.jsp</result> <result name="update">/admin/page/commentsUpdate.jsp</result> </action> |
在这个Action中引用了2个拦截器,一个是默认的注入拦截器defaultStack,另一个就是令牌拦截器token,之后还定义了一个重复提交后的返回地址invalid.token。
之后在页面表单form中加入<s:token></s:token>就可以了。
- <meta http-equiv="X-UA-Compatible" content="IE=7" />的意思
X-UA-Compatible是针对ie8新加的一个设置,对于ie8之外的浏览器是不识别的,这个区别与content="IE=7"在无论页面是否包含<!DOCTYPE>指令,都像是使用了 Windows Internet Explorer 7的标准模式。而content="IE=EmulateIE7"模式遵循<!DOCTYPE>指令。对于多数网站来说,它是首选的兼容性模式。
目前IE8尚在测试版中,所以为了避免制作出的页面在IE8下面出现错误,建议直接将IE8使用IE7进行渲染。也就是直接在页面的header的meta标签中加入如下代码:
<meta http-equiv="X-UA-Compatible" content="IE=7" /> |
这样我们才能使得页面在IE8里面表现正常!
- Js比较数值大小
在JS中比较数字大小的时候一般人都会用
If(a >= b){ …… } |
这是错误的,这比较是从第一个字符串开始比较。
应该用
If(a - b >= 0){ …… } |
进行数值比较
声明:本文为网络转载,如果侵犯版权,将及时删除……不负任何法律责任。