Struts2(3)


   使用Struts2完成对客户的查询操作

案例一: 使用Struts2完成对客户的查询操作
1.1 案例需求
1.1.1   需求概述
CRM系统中客户信息管理模块功能包括:
新增客户信息
客户信息查询
修改客户信息
删除客户信息

本功能要实现查询客户,页面如下:


1.2 相关知识点
1.2.1   OGNL的概述
1.2.1.1 什么是OGNL

1.2.1.2 OGNL的作用
   1、支持对象方法调用,如xxx.doSomeSpecial(); 
   2、支持类静态的方法调用和值访问,表达式的格式:
      @[类全名(包括包路径)]@[方法名 |  值名],例如:
             @java.lang.String@format('foo %s', 'bar')
             或@tutorial.MyConstant@APP_NAME;
      设置 struts.ognl.allowStaticMethodAccess=true
   3、访问OGNL上下文(OGNL context)和ActionContext;访问值栈
   4、支持赋值操作和表达式串联,如price=100, discount=0.8,
        calculatePrice(),这个表达式会返回805、操作集合对象。
1.2.1.3 OGNL的入门:
    @Test
    // OGNL调用对象的方法:
    public void demo1() throws OgnlException{
        OgnlContext context = new OgnlContext();
        Object obj = Ognl.getValue("'helloworld'.length()", context, context.getRoot());
        System.out.println(obj);
    }

    @Test
    // OGNL获取数据:
    public void demo3() throws OgnlException{
        OgnlContext context = new OgnlContext();

        // 获取OgnlContext中的数据:
        /*context.put("name", "张三");
        String name = (String) Ognl.getValue("#name", context, context.getRoot());
        System.out.println(name);*/

        // 获得Root中的数据
        User user = new User();
        user.setName("李四");
        context.setRoot(user);

        String name = (String) Ognl.getValue("name", context, context.getRoot());
        System.out.println(name);
    }
1.2.2   值栈的概述
1.2.2.1 什么是值栈? 
    ValueStack是Struts的一个接口,字面意义为值栈,OgnlValueStack是ValueStack的实现类,客户端发起一个请求struts2架构会创建一个action实例同时创建一个OgnlValueStack值栈实例,OgnlValueStack贯穿整个 Action 的生命周期,struts2中使用OGNL将请求Action的参数封装为对象存储到值栈中,并通过OGNL表达式读取值栈中的对象属性值。
1.2.2.2 值栈的内部结构:

在 OnglValueStack 中包括两部分,值栈和map(即ognl上下文)


   Context: 即OgnlContext上下文,它是一个map结构,上下文中存储了一些引用,parameters、request、session、application等,上下文的Root为CompoundRoot。
OgnlContext中的一些引用:
        parameters: 该 Map 中包含当前请求的请求参数
        request: 该 Map 中包含当前 request 对象中的所有属性
        session: 该 Map 中包含当前 session 对象中的所有属性
        application:该 Map 中包含当前 application  对象中的所有属性
        attr: 该 Map 按如下顺序来检索某个属性: request, session, application

   CompoundRoot:存储了action实例,它作为OgnlContext 的Root对象。
        CompoundRoot 继承ArrayList实现压栈和出栈功能,拥有栈的特点,先进后出,后进先出,最后压进栈的数据在栈顶。我们把它称为对象栈。

    struts2对原OGNL作出的改进就是Root使用CompoundRoot(自定义栈),使用OnglValueStack的findValue方法可以在CompoundRoot中从栈顶向栈底找查找的对象的属性值。

    CompoundRoot作为OgnlContext 的Root对象,并且在CompoundRoot中action实例位于栈顶,当读取action的属性值时会先从栈顶对象中找对应的属性,如果找不到则继续找栈中的其它对象,如果找到则停止查找。

1.2.2.3 ActionContext和ValueStack的关系:
通过源码查询:
    public ActionContext createActionContext(HttpServletRequest request, HttpServletResponse response) {
        ActionContext ctx;
        Integer counter = 1;
        Integer oldCounter = (Integer) request.getAttribute(CLEANUP_RECURSION_COUNTER);
        if (oldCounter != null) {
            counter = oldCounter + 1;
        }

        ActionContext oldContext = ActionContext.getContext();
        if (oldContext != null) {
            // detected existing context, so we are probably in a forward
            ctx = new ActionContext(new HashMap(oldContext.getContextMap()));
        } else {
            ValueStack stack = dispatcher.getContainer().getInstance(ValueStackFactory.class).createValueStack();
            stack.getContext().putAll(dispatcher.createContextMap(request, response, null));
            ctx = new ActionContext(stack.getContext());
        }
        request.setAttribute(CLEANUP_RECURSION_COUNTER, counter);
        ActionContext.setContext(ctx);
        return ctx;
    }
* 在创建ActionContext的时候 创建ValueStack的对象,将ValueStack对象给ActionContext.
* ActionContext中有一个ValueStack的引用.  ValueStack中也有一个ActionContext的引用.
* ActionContext获取ServletAPI的时候,依赖值栈了.
1.2.2.4 获取值栈对象:
【通过ActionContext对象获取值栈.】
ValueStack stack1 =ActionContext.getContext().getValueStack();

【通过request域获取值栈.】
ValueStack stack2 = (ValueStack) ServletActionContext.getRequest().getAttribute(ServletActionContext.STRUTS_VALUESTACK_KEY);
1.2.2.5 操作值栈:
【对Action中的属性提供get方法的方式】
因为Action本身在值栈中,Action中的属性也就默认在值栈中了,所以我们可以通过对Action的属性提供get方法的方式来操作值栈。
【手动操作值栈】
调用值栈的push和set方法对值栈进行操作
1.2.2.6 从值栈中获取数据

1.2.2.7 EL能够访问值栈
底层对Request对象的getAttribute方法进行增强:
public class StrutsRequestWrapper extends HttpServletRequestWrapper {

    private static final String REQUEST_WRAPPER_GET_ATTRIBUTE = "__requestWrapper.getAttribute";
    private final boolean disableRequestAttributeValueStackLookup;

    /**
     * The constructor
     * @param req The request
     */
    public StrutsRequestWrapper(HttpServletRequest req) {
        this(req, false);
    }

    /**
     * The constructor
     * @param req The request
     * @param disableRequestAttributeValueStackLookup flag for disabling request attribute value stack lookup (JSTL accessibility)
     */
    public StrutsRequestWrapper(HttpServletRequest req, boolean disableRequestAttributeValueStackLookup) {
        super(req);
        this.disableRequestAttributeValueStackLookup = disableRequestAttributeValueStackLookup;
    }

    /**
     * Gets the object, looking in the value stack if not found
     *
     * @param key The attribute key
     */
    public Object getAttribute(String key) {
        if (key == null) {
            throw new NullPointerException("You must specify a key value");
        }

        if (disableRequestAttributeValueStackLookup || key.startsWith("javax.servlet")) {
            // don't bother with the standard javax.servlet attributes, we can short-circuit this
            // see WW-953 and the forums post linked in that issue for more info
            return super.getAttribute(key);
        }

        ActionContext ctx = ActionContext.getContext();
        Object attribute = super.getAttribute(key);

        if (ctx != null && attribute == null) {
            boolean alreadyIn = isTrue((Boolean) ctx.get(REQUEST_WRAPPER_GET_ATTRIBUTE));

            // note: we don't let # come through or else a request for
            // #attr.foo or #request.foo could cause an endless loop
            if (!alreadyIn && !key.contains("#")) {
                try {
                    // If not found, then try the ValueStack
                    ctx.put(REQUEST_WRAPPER_GET_ATTRIBUTE, Boolean.TRUE);
                    ValueStack stack = ctx.getValueStack();
                    if (stack != null) {
                        attribute = stack.findValue(key);
                    }
                } finally {
                    ctx.put(REQUEST_WRAPPER_GET_ATTRIBUTE, Boolean.FALSE);
                }
            }
        }
        return attribute;
    }
}
1.2.3   EL的特殊字符的使用:
1.2.3.1 #号的使用:
【获取context的数据】

【用于构建一个Map集合】:使用struts的UI标签的时候.
"#{'aaa':'111','bbb':'222','ccc':'333' }" var="entry">
    "key"/>---"value"/>
"#entry.key"/>---"#entry.value"/>
"#{'1':'男','2':'女' }" name="sex"> 1.2.3.2 %号的使用: 【%强制解析OGNL表达式】 "name" value="%{#request.name}"/> 【%强制不解析OGNL表达式】 "%{'#request.name'}"/> 1.2.3.3 $号的使用: 【在配置文件中使用OGNL表达式】 在struts的配置文件中使用.XML文件 或者 是属性文件. 1.3 案例实现 1.3.1 环境准备 1.3.2 代码实现 片

你可能感兴趣的:(web基础到开发,后端哪些事)