jsp视图层底层原理(struts2)

  1. 说明:展示jsp中el表达式取值底层过程。说是底层原理有点过,不过底层原理就蕴含其中。
  2. 自行甄别。
  3. 主代码如下:
  4. 原理分析,showFindUser.jsp中展示el取值的底层实现过程或原理。
=================================3.主代码===============================
一、视图层:


    (1).findUser.jsp >>>>>>
    <%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%
    String basePath = request.getScheme()+"://"
                + request.getServerName() +":"
                +request.getServerPort() +"/"
                + request.getContextPath()+"/";
%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<!-- 重写href,作为相对路径 -->
 <base href="<%=basePath%>">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>findUser.jsp</title>
</head>
<body>
    <form action="findUser.action" method="get">
        <!-- ognl形式传参 -->
        <input type="text" name="user.id" /><br/>
        <input type="submit" value="查看用户" /><br/>
    </form>
</body>
</html>


    (2).showFindUser.jsp >>>>>>>

    <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"
    import="java.util.*"
    import="com.opensymphony.xwork2.ognl.OgnlValueStack"
    import="com.opensymphony.xwork2.util.CompoundRoot"
    import="org.yl.action.UserAction"
    import="org.yl.domain.User"


%>
<!-- 引入struts2标签库 -->
<%@ taglib uri="/struts-tags" prefix="s" %>
<%
  String basePath = request.getScheme()+"://"
                + request.getServerName() +":"
                +request.getServerPort() +"/"
                + request.getContextPath()+"/";
%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
 <base href="<%=basePath%>">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
    <h1>视图层:JSP,从ValueStack中的CompoundRoot中取值</h1>

    <div>
        <span>用户信息:</span><br/>
        <!-- 1.java直接取值 -->
        <%
            OgnlValueStack vs = (OgnlValueStack)request.getAttribute("struts.valueStack");
            //值栈的上下文
            Map<String,Object> vsContext = vs.getContext();
            for(Map.Entry<String, Object> entry: vsContext.entrySet()){
                //System.out.println("key:" + entry.getKey() + "--value:" + entry.getValue() + "\n");
            }
            //值栈的根(CompoundRoot数据结构为栈,使用ArrayList实现的)
            CompoundRoot root = vs.getRoot();
            Object obj = root.peek();//从root栈中取出一个数据
            UserAction userAction = null;
            User user = null;
            String name = null;
            if(obj instanceof UserAction){
                userAction = (UserAction)obj;
                user = userAction.getUser();
                System.out.println("Action中的成员变量信息:" +"\n"
                            + "1.user信息 ======"
                            + "id:" + user.getId() + "\n"
                            + "name:" + user.getName() + "\n"
                            + "sex:" + user.getSex() + "\n"
                            + "deposit:" + user.getDeposit() + "\n"
                            + "telephone:" + user.getTelephone() + "\n"
                            +"");
                name = user.getName();//供页面使用,与html标签进行整合
            }

        %>
        java直接取值:<input type="text" value="<%=name %>" readonly="readonly" /><br/>

        <!-- 2.标签库解药or毒药 -->
        <!-- el表达式 -->
        el表达式取值:<input type="text" value="${user.name }" readonly="readonly" /><br/>

        <!-- 使用struts2标签库中的标签 
        <s:property value="user.telephone"/><br/>-->
        struts2标签取值:<input type="text" value="<s:property value="user.telephone"/>" readonly="readonly" /><br/>

    </div>

</body>
</html>




二、控制层




/**
 * 演示:显示层从ValueStack中取值
 *  (1)el+jstl
 *  (2)struts2标签库+Ognl
 * @author 拈花为何不一笑
 *
 */
public class UserAction {//何时何地创建Action?服务Action时创建ActionProxy,
    //而在创建代理时ObjectFactory创建Action并且把Action放入至值栈中(实际是放入CompoundRoot中)
    //何地?DefaultActionInvocation作为场地

    //初始化
    private User user = new User();


    //业务方法(struts.xml的UserAction配置中不指定具体方法时,excute或doExecute作为默认方法)
    public String doExecute(){//执行action阶段调用
        System.out.println("findUser...");


        /**
         * 下面逻辑发生在拦截器阶段
         * 1.xwork2的InstantiatingNullHandler类调用对象工厂objectFactory.buildBean(clazz, context);
         * 来创建了UserAction中为空的成员属性User:user。
         * 2.当UserAction中的成员属性是类对象时且开发人员没有初始化时,
         *  由Ognl+CompoundRootAccessor+InstantiatingNullHandler经过一系列逻辑创建了该成员属性
         *  创建User实例后,再通过Ognl把前端传递过来的参数值:user.id="m-p6"赋给User对象中的成员变量id。
         * 3.由于步骤2开销不少,建议开发中先初始化Action中的成员变量(类对象作为Action的成员变量),避免程序执行步骤2
         */
        if(this.user != null){//UserAction中的User实例也被框架创建了。(谁创建的?在哪创建的?)
            System.out.println("user.id:" + this.user.getId());
            //模拟从DB或企业信息系统中获取到的数据
            if(user.getId().equals("1688")){
                this.user.setName("张天见");
                this.user.setSex("男");
                this.user.setTelephone("13638885606");
                this.user.setDeposit(73000);
            }
        }


        //struts2中提供与Web容器直接交互的类:ServletActionContext
        //获取服务器路径
        /*HttpServletRequest request =ServletActionContext.getRequest();
        String serverPath = request.getSession().getServletContext().getRealPath("/");
        System.out.println("serverPath: " + serverPath);*/

        return "showFindUser";
    }


    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }


}



三、模型层




public class User {

    private String id;  //身份证

    private String name;

    private String address;

    private String telephone;

    private String sex;

    private long deposit;   //存款

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public String getTelephone() {
        return telephone;
    }

    public void setTelephone(String telephone) {
        this.telephone = telephone;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public long getDeposit() {
        return deposit;
    }

    public void setDeposit(long deposit) {
        this.deposit = deposit;
    }


}



配置文件:   
<?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>
    <!-- 常量bean配置 -->
    <constant name="struts.devMode" value="true" />
    <!-- action事件映射 -->
    <package name="default" namespace="/" extends="struts-default">
       <action name="reg" class="org.yl.action.Register">
          <result name="success">/success.jsp</result>
        </action>

       <action name="findUser" class="org.yl.action.UserAction">
          <result name="showFindUser">/showFindUser.jsp</result>
        </action>


    </package>

</struts>

===========================4.jsp中el取值底层实现或原理=========================
jsp视图层中几种取值方式的底层原理(Struts2)
    环境:tomcat,win7
    1.tomcat中的jasper作为引擎解析jsp文件
        (1)jsp文件被解析成java文件,这个java文件解析jsp分为两部分:jsp中的html和jsp中的java代码
        (2)html代码通过JspWtriter直接输出到浏览器,java代码被编译执行作为结果嵌入html中。
        (3)输出到浏览器中的html文件,被浏览器解析,呈现出UI界面。

        tips:说标签库或许你感受不深,那换一种说法你肯定会熟悉:视图层组件。(放个点在此)
    2.一探,jasper解析jsp后生成的java文件,若jsp中有el表达式取值。则反应到这个java文件中是如何进行的?
        此showFindUser_jsp.java(解析showFindUser.jsp得到的java文件)文件片段:
            //通过jsp内置对象获取输出字符流JspWriter
             JspWrite out = pageContext.getOut();
             out.write("\t\t<!-- 2.标签库解药or毒药 -->\r\n");
              out.write("\t\t<!-- el表达式 -->\r\n");
              out.write("\t\tel表达式取值:<input type=\"text\" value=\"");
              out.write((java.lang.String) org.apache.jasper.runtime.PageContextImpl.proprietaryEvaluate("${user.name }", java.lang.String.class, (PageContext)_jspx_page_context, null, false));
              out.write("\" readonly=\"readonly\" /><br/>\r\n");
              out.write("\t\t\r\n");
    3.el取值流程,PageContextImpl.proprietaryEvaluate("${user.name }", java.lang.String.class, (PageContext)_jspx_page_context, null, false));
    如下:
类:PageContextImpl中的进行以下逻辑:
 调用proprietaryEvaluate(final String expression, 
                                             final Class expectedType,
                                             final PageContext pageContext,
                                             final ProtectedFunctionMapper functionMap,
                                             final boolean escape))方法
类:ExpressionEvaluatorImpl中进行了以下逻辑:
    解析表达式:Object parsedValue = parseExpressionString (pExpressionString);
    表达式取值: Object value = ((Expression) parsedValue).evaluate (pResolver, functions, pLogger);

        (类:ComplexValue extends Expression,表示一个动态值,它由一个前缀和一组可选的ValueSuffix元素组成。
        前缀类似于标识符,后缀类似于“属性”或“索引元素”运算符。)
类:VariableResolverImpl 基于jstl实现的变量解析器
    1.这里有大家熟悉的取值顺序,从隐式对象中取值:pageContext/pageScope/requestScope/sessionScope/applicationScope/
    param/paramValues/header/headerValues/initParam/cookie
    2.若不在其中,就在页面上下文中查找即可PageContext.findAttribute (pName);

类:又回到PageContextImpl中的进行以下逻辑:   
    1.在doFindAttribute(name)方法中查看值
    2.它是先从request中取值request.getAttribute(name);而这个request是被装饰了的StrutsRequestWrapper
        从这里开始,el表达式取值就与struts2联系上了。

类: StrutsRequestWrapper extends HttpServletRequestWrapper进行了以下逻辑:
    //从request(ServletRequestWrapper)中取值(User)
    Object attribute = super.getAttribute(s);
    //若request中没值,则从值栈OgnlValueStack中取值(结合Ongl)
    //有了值栈和Ognl,从struts2中取数据简单是易如反掌,屡试不爽。(不细说,前面文章有写)
    ValueStack stack = ctx.getValueStack();
    if (stack != null) {
        attribute = stack.findValue(s);
    }
类:JspContextWrapper进行了以下逻辑:
  1.evaluate方法中,通过上面获取到的User实例对象,
    与BeanInfoManager获取User的bean信息(如getName()),结合反射取出user.name的值
  2.取出的值放置到showFindUser_jsp.java(japser解析jsp后生成的文件)文件中





**tips:里面包含了不少东西,比如struts2中的实现具体细节描述。**
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值