本文为转载Web常使用的功能经验笔记第1季 转载自刘岩

Web常使用的功能经验笔记第1 

刘岩

Emailsuhuanzheng7784877@163.com

  1. 前言

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……)使用经验做个总结,希望与您有个共鸣。

  1. 判断标签<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>

  1. 在页面中访问变量(#、%、$)

OGNL是通常要结合Struts 2的标志一起使用。主要是#、%和$这三个符号的使用。

一般使用JSP内置对象域的变量的时候(application、session、request、parameters)都需要使用Struts标签+#来进行访问,一般用于访问Session里面的变量。

例如:

<s:if test="%{#session.customer!=null}">

或者

<s:property value="%{#application.myApplicationAttribute}" />
<s:property value="%{#session.mySessionAttribute}" />
<s:property value="%{#request.myRequestAttribute}" />
<s:property value="%{#parameters.myParameter}" />

在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)上的一段话

“#”主要有三种用途:
1.访问OGNL上下文和Action上下文,#相当于ActionContext.getContext();下表有几个ActionContext中有用的属性:  

名称 作用 例子
parameters:包含当前HTTP请求参数的Map

#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};
3.构造Map,如#{'foo1':'bar1', 'foo2':'bar2'}。

“%”符号的用途是在标志的属性为字符串类型时,计算OGNL表达式的值。

“$”有两个主要的用途,用于在国际化资源文件中,引用OGNL表达式。在Struts 2配置文件中,引用OGNL表达式。

  1. 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" />

  1. 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

  1. 利用Struts2错误标签显示Action中显示发生的错误

<s:fielderror>

    <s:param>errorMessage</s:param>

</s:fielderror>

其中errorMessage是Action中错误域中的key。

  1. 利用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>

  1. 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格式字符串。前端如何解析,就是前端的事情了。

  1. 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和你自己定义的拦截器!然后你需要用这个拦截器的包都继承这个包就好了!

  1. 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>就可以了。

  1. <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里面表现正常!

  1. Js比较数值大小

在JS中比较数字大小的时候一般人都会用

If(a >= b){

    ……

}

这是错误的,这比较是从第一个字符串开始比较。

应该用

If(a - b >= 0){

    ……

}

进行数值比较

声明:本文为网络转载,如果侵犯版权,将及时删除……不负任何法律责任。

I believe that we are who we choose to be. Nobody‘s going to come and save you, you‘ve got to save yourself. 我相信我们成为怎样的人是我们自己的选择。没有人会来拯救你,你必须要自己拯救自己。
原文地址:https://www.cnblogs.com/caroline/p/2048653.html