Struts2_ognl表達(dá)式&操作值棧

Struts2_OGNL表達(dá)式

一蝶锋、初步使用ongl表達(dá)式

OGNL是Object Graphic Navigation Language(對(duì)象圖導(dǎo)航語言)的縮寫砚偶,是一個(gè)使用簡單逗旁、功能強(qiáng)大的、開源的表達(dá)式語言(框架),可以方便地操作任何的對(duì)象屬性、方法等揣非。

Struts2框架使用OGNL作為默認(rèn)的表達(dá)式語言,主要用于頁面的取值躲因。它類似于EL表達(dá)式語言早敬,但比EL語法強(qiáng)大很多。

EL Expression Language 表達(dá)式語言大脉, 主要用來獲取 JSP頁面四個(gè)域范圍數(shù)據(jù) (page搞监、 request、 session箱靴、 application )

使用ongl表達(dá)式

1. 導(dǎo)入的jar包:
    ognl-xxx.jar : ognl的核心環(huán)境
    javassist-xxx.jar : ognl的依賴,提供字節(jié)碼修改能力荷愕。

2. 使用ognl表達(dá)式的jsp頁面需要導(dǎo)入struts2的標(biāo)簽庫
    <%@ taglib prefix="s" uri="/struts-tags"%>

3. 幾種基本的使用方式:
    1. Java對(duì)象的直接訪問 :
        <s:property value="'name'"/><br/>
    
    2. 實(shí)例方法調(diào)用
        <s:property value="'name'.length()"/><br/>      

    3. 賦值操作或表達(dá)式串聯(lián)
        <s:property value="1+1" /><br/>

    4. 靜態(tài)方法調(diào)用(類的靜態(tài)方法或靜態(tài)變量的訪問) 不推薦
        語法:@[類全名(包括包路徑)]@[方法名|值名]
        例如:<s:property value="@java.lang.Math@max(10,20)"/><br/>

        但是:饣场!安疗!在使用靜態(tài)方法之前必須在struts.xml中開啟靜態(tài)方法調(diào)用功能
        <!-- 開啟ognl表達(dá)式靜態(tài)方法調(diào)用 -->
        <constant name="struts.ognl.allowStaticMethodAccess" value="true"></constant>


    5. OGNL上下文(OGNL Context)和ActionContext的訪問抛杨。(值棧相關(guān)訪問-重要)
    6. 集合對(duì)象的操作

二、值棧

值棧的概念

值棧(ValueStack)荐类,是Struts2的數(shù)據(jù)中轉(zhuǎn)站怖现,其中自動(dòng)保存了當(dāng)前Action對(duì)象和其他相關(guān)對(duì)象(包括常用的Web對(duì)象的引用,如request等)玉罐,也可以手動(dòng)保存自己的數(shù)據(jù)對(duì)象屈嗤,同時(shí)也可以隨時(shí)隨地將對(duì)象從值棧取出或操作(通過OGNL表達(dá)式)

了解:值棧的生命周期,和request一樣或action吊输,生命周期都一樣

獲取值棧對(duì)象

在Action動(dòng)作類中獲取值棧對(duì)象有兩種方式:

@Override
public String execute() throws Exception {

    //目標(biāo) :獲取值棧對(duì)象
    //方式一 : 通過request對(duì)象直接獲取
    ValueStack valueStack = (ValueStack) ServletActionContext.getRequest().getAttribute("struts.valueStack");
    
    //方式二 : 通過struts2提供的api來獲取(底層還是1方式)
    ValueStack valueStack2 = ActionContext.getContext().getValueStack();
    
    //測試是否是同一個(gè)對(duì)象
    System.out.println(valueStack == valueStack2);
    return NONE;
}

值棧的數(shù)據(jù)存儲(chǔ)結(jié)構(gòu)

在值棧的內(nèi)部有兩個(gè)邏輯部分:

  • ObjectStack(對(duì)象棧):保存了Action的相關(guān)對(duì)象和動(dòng)作饶号,數(shù)據(jù)存儲(chǔ)結(jié)構(gòu)是List。
  • ContextMap(上下文棧):保存了各種映射關(guān)系季蚂,如常用的web對(duì)象的引用茫船,數(shù)據(jù)存儲(chǔ)結(jié)構(gòu)是Map。

    值棧ValueStack(OgnlValueStack實(shí)現(xiàn)類)中有兩塊區(qū)域 :
    一塊是CompoundRoot對(duì)象棧(也稱為Root棧),它實(shí)質(zhì)上是使用List集合來存放對(duì)象,存入對(duì)象壓棧從棧頂往下壓扭屁。

    一塊是OgnlContext上下文棧(也稱為Map棧)算谈。
        Map棧中有兩個(gè)區(qū)域,_root用于存放對(duì)象棧(Root棧)的引用
        _values實(shí)質(zhì)上使用Map集合鍵值對(duì)的形式存放對(duì)象
img12.png

值棧是在請(qǐng)求對(duì)象引用了一塊存儲(chǔ)空間。

值棧包括兩部分: 對(duì)象棧(CompoundRoot料滥,繼承List接口)和OGNL上下文棧(OgnlContext然眼,實(shí)現(xiàn)Map接口)
而OGNL上下文棧內(nèi)部又分為兩部分:對(duì)象棧的引用和一個(gè)HashMap,這個(gè)HashMap會(huì)引用常用web對(duì)象和其他映射關(guān)系葵腹。

三罪治、 操作值棧

棧的概念:
棧是一種數(shù)據(jù)結(jié)構(gòu)丽声,它按照先進(jìn)后出的原則存儲(chǔ)數(shù)據(jù)难裆,即先進(jìn)入的數(shù)據(jù)被壓入棧底呢蛤,
最后進(jìn)入的數(shù)據(jù)在棧頂,需要讀取數(shù)據(jù)的時(shí)候久脯,從棧頂開始彈出數(shù)據(jù)(即最后一個(gè)數(shù)據(jù)被第一個(gè)讀出來)晒骇。

棧也被成為先進(jìn)后出表霉撵,可進(jìn)行插入和刪除操作,插入稱之為進(jìn)棧(壓棧)(push)洪囤,
刪除稱之為退棧(pop)徒坡,允許操作的兩端分別稱為棧頂(top)和棧底(bottom)。棧底固定瘤缩,而棧頂浮動(dòng)喇完。

對(duì)于棧就只能每次訪問它的棧頂元素,從而可以達(dá)到保護(hù)棧頂元素以下的其他元素的目的剥啤。

值棧數(shù)據(jù)的保存:向root棧和map棧放入數(shù)據(jù)

@Override
public String execute() throws Exception {

    // 目標(biāo) :向root棧和map棧中分別存入數(shù)據(jù)
    String msg = "我愛java";
    
    // 獲取值棧對(duì)象
    ValueStack valueStack = ActionContext.getContext().getValueStack();
    
    //向root棧中存值(壓棧),匿名,
    valueStack.push(msg);
    //root棧中存值(壓棧),有名字
    valueStack.set("msg2", "我愛C++");
    //向Root棧中存值(鍵值對(duì))
    ActionContext.getContext().put("msg3", "我愛Python");

    return SUCCESS;
}

通過ognl表達(dá)式取出存儲(chǔ)在值棧中的數(shù)據(jù)顯示在頁面

struts.xml 配置跳轉(zhuǎn)頁面 :
    <action name="valueStack2" class="com.itdream.a_valueStack.ValueStack2Action">
            <result>/a_ognl/result.jsp</result>
    </action>


result.jsp : 

<%@ taglib prefix="s" uri="/struts-tags"%>

<!-- 取出存在值棧中的值 -->
<!-- push方法,匿名壓入Root棧的數(shù)據(jù),第一個(gè)被壓入 -->
<s:property value="[1].top"/><br/>

<!-- set方法,Struts2幫我們創(chuàng)建一個(gè)map集合存儲(chǔ)數(shù)據(jù)壓入Root棧的數(shù)據(jù),map的key就是數(shù)據(jù)的名字,通過key取值 -->
<s:property value="msg2"/><br/>

<!-- put方法,放入Map棧中,通過加#號(hào)定向到Map棧中找 -->
<!-- 也可以不加#號(hào)使用默認(rèn)查找機(jī)制,但這樣先從Root棧先找,再到Map棧找key,如果在Root棧找到就找不到Map棧的數(shù)據(jù)了 -->
<s:property value="#msg3"/>|<s:property value="msg3"/><br/>

<!-- 用來查看值棧的內(nèi)容 -->
<s:debug/>
img14.png

點(diǎn)擊Debug查看值棧的內(nèi)容:

頁面中直接查看值棧的元素的方法锦溪。
struts2為我們提供了一個(gè)標(biāo)簽:<s :debug/>,只要將其加在頁面中即可府怯。

Root棧:

數(shù)據(jù)從棧頂往下壓刻诊,push方法直接壓入String對(duì)象,此時(shí)它是棧頂,索引為0
然后使用set方法,創(chuàng)建了一個(gè)HashMap存儲(chǔ)數(shù)據(jù)的值,作為對(duì)象存入Root棧,此時(shí)棧頂是這個(gè)HashMap對(duì)象,String對(duì)象的索引變?yōu)?
img15.png

Map棧:

put方法,以鍵值對(duì)形式存儲(chǔ)數(shù)據(jù)
img16.png

在這里介紹值棧的創(chuàng)建過程:

1. 每次請(qǐng)求都會(huì)創(chuàng)建一個(gè)ActionContext對(duì)象和一個(gè)OnglValueStack值棧對(duì)象,這時(shí)在Root棧中放入了一個(gè)textProvider.

2. 緊接著,Struts2將與Servket有關(guān)的Response,Request,Session等對(duì)象放入到Map棧中,此時(shí)Map棧中有Servlet的對(duì)象引用.

3. 之后就準(zhǔn)備執(zhí)行Action動(dòng)作類 ,創(chuàng)建Action動(dòng)作的代理對(duì)象。Action是在執(zhí)行的時(shí)候才進(jìn)行初始化牺丙,初始化完成后,
將Action對(duì)象壓入Root棧棧頂,并在Map棧的_root中放入一個(gè)引用:key - action

到這里,Root棧中有一個(gè)textProvider與一個(gè)Action對(duì)象,Map棧中有Servlet相關(guān)的數(shù)據(jù)以及Action對(duì)象的引用则涯,
兩個(gè)Action是同一個(gè)

4. 初始化完成,ActionProxy代理對(duì)象在執(zhí)行時(shí),會(huì)先執(zhí)行攔截器冲簿,再執(zhí)行Action,
這個(gè)時(shí)候,如果有Action實(shí)現(xiàn)了ModelDriven接口,模型驅(qū)動(dòng)攔截器就將模型對(duì)象壓入棧頂粟判。


了解原理的目的:

知道值棧的初始化時(shí)機(jī),訪問action的時(shí)候峦剔,才創(chuàng)建(這個(gè)過程中會(huì)創(chuàng)建actionProxy對(duì)象浮入,并且同時(shí)創(chuàng)建值棧,并且羊异,將一些對(duì)象放入值棧事秀。)

值棧初始化之后,里面主要默認(rèn)有:root棧(textProvider野舶、action類對(duì)象易迹、model(user)),map棧(servlet相關(guān)對(duì)象平道、action對(duì)象一個(gè)引用)

哪些對(duì)象在棧頂睹欲!因?yàn)楹竺嫖覀儚闹禇H≈担紡臈m斖氯 K跃酱欢ㄒ滥膫€(gè)對(duì)象在棧上面袋哼。
img13.png

值棧的默認(rèn)搜索機(jī)制

測試代碼:

    
    public class ValueStack3Action extends ActionSupport {
        
        // 目標(biāo) : 測試值棧的默認(rèn)查找機(jī)制
        // 提供Action的屬性,Action初始化完成時(shí),會(huì)將Action的對(duì)象屬性壓入Root棧
        private String username = "林志玲";
    
        public String getUsername() {
            return username;
        }
    
        public void setUsername(String username) {
            this.username = username;
        }
    
        @Override
        public String execute() throws Exception {
    
            ValueStack valueStack = ActionContext.getContext().getValueStack();
            //在創(chuàng)建一個(gè)有名字的對(duì)象壓入Root棧
            valueStack.set("username", "唐嫣");
            
            //往Map棧存入數(shù)據(jù)
            ActionContext.getContext().put("username", "高圓圓");
            
            return SUCCESS;
        }
    }


    jsp頁面:

    <!-- 取出存在值棧中的值 -->
    <s:property value="username"/>
    
    <!-- 用來查看值棧的內(nèi)容 -->
    <s:debug/>


    此時(shí)運(yùn)行取出username的值是 唐嫣 。

    為什么呢闸衫?這是由于值棧的默認(rèn)查找機(jī)制涛贯。
    當(dāng)我們使用 對(duì)象名稱 直接查找時(shí),底層使用的API是valuestack.find(ognl)
    1. 他會(huì)優(yōu)先從Root棧中開始查找(從上而下),因?yàn)锳ction屬性存入值棧的是在執(zhí)行前壓入的,因此取的時(shí)候,它在值棧的下方,
    因此首先找到上面的執(zhí)行時(shí) set 方法放入的 username。

    2. 如果Root棧找不到,才會(huì)找Map棧中的key.如果想直接獲取Map棧中的數(shù)據(jù),加個(gè)#號(hào)即可
        <s:property value="#username"/>
    

OGNL操作值棧的幾個(gè)符號(hào):

直接使用對(duì)象名 蔚出, # 弟翘, % , $

1. 直接使用對(duì)象名,使用值棧的默認(rèn)查找機(jī)制

2. #+key 從Map棧中查找對(duì)象的key,從而找到該數(shù)據(jù)
    1. 通過#request等可以獲取存儲(chǔ)在Servlet域?qū)ο笾械臄?shù)據(jù)

3. % , 控制解析或者不解析

    添加%{'對(duì)象名'}或者'對(duì)象名'讓其變成普通字符串而不解析 骄酗。
    <!-- %強(qiáng)制不轉(zhuǎn)換 -->
    <s:property value="username"/> <!-- 唐嫣 -->
    <s:property value="'username'"/><!-- username -->
    <s:property value="%{'username'}"/><!-- username -->

    使用%{對(duì)象名}強(qiáng)制解析
    <!-- 這里s:textfield標(biāo)簽類似與input的text標(biāo)簽 -->
    <s:textfield value="username"/>
    <!-- textfield標(biāo)簽的value中直接寫對(duì)象名稱不會(huì)進(jìn)行解析,需要%強(qiáng)制解析 -->
    <s:textfield value="%{username}"/>

4. $用于在配置文件中獲取值棧的值
    
    1.URL請(qǐng)求重定向時(shí)稀余,攜帶(動(dòng)態(tài)傳遞)參數(shù) –struts.xml中使用
        result type="redirect">/c_expr/ognl2.jsp?name=${myname}</result>

值棧的存取匯總小結(jié)

值棧的主要作用就是數(shù)據(jù)的保存和獲取(可以在任何地方獲惹鞣)睛琳。

1.如何向值棧保存數(shù)據(jù)
  • ValueStack.put(obj):保存數(shù)據(jù)到Root棧(棧頂),(對(duì)象本身)匿名,通過索引取出
  • ValueStack.set(key,value):保存數(shù)據(jù)到Root棧(棧頂),數(shù)據(jù)被自動(dòng)封裝成一個(gè)Map集合存儲(chǔ),棧頂保存的是一個(gè)Map集合,Map的value就是對(duì)象,這種存儲(chǔ)方式有名字.ognl通過名稱獲取數(shù)據(jù)的值
  • ActionContext.getContext().put(key,value): 保存數(shù)據(jù)到Map棧中
  • 提供Action成員變量,提供getter方法(Action就在root棧中踏烙,Action屬性可以被搜索)

模型驅(qū)動(dòng)封裝參數(shù)優(yōu)先于屬性驅(qū)動(dòng)的原理:


    第四種方式在初始化完成時(shí)壓入Root棧,而ModelDriven過濾器待封裝的參數(shù),在初始化完成后,過濾器中,將其壓入棧頂师骗。
    而封裝的參數(shù)從Root棧中取值是自上而下取值的,因此模型驅(qū)動(dòng)優(yōu)先于屬性驅(qū)動(dòng)。
2. ognl表達(dá)式如何獲取值棧的數(shù)據(jù)
  • JSP頁面獲取
    • <s :property value= “對(duì)象名”/> 先搜索root棧對(duì)象屬性(getter方法: getXxx-->xxx)宙帝,再搜索map的key
    • <s :property value= “#對(duì)象名”/>搜索map棧的key
    • 通過[index].top指定訪問Root棧的某個(gè)對(duì)象,例如[0].top訪問棧頂對(duì)象
  • Action代碼獲取
    • ValueStack.findValue(ognl表達(dá)式) ; 獲取值棧數(shù)據(jù)
3. 值棧的生命周期
* 貫穿整個(gè)Action的生命周期丧凤,每個(gè)Action類的對(duì)象實(shí)例都擁有一個(gè)ValueStack對(duì)象募闲。
* Struts2框架將ValueStack對(duì)象保存在名為“struts.valueStack”的請(qǐng)求(request)屬性中步脓,
即值棧是request中的一個(gè)對(duì)象,一個(gè)請(qǐng)求對(duì)應(yīng)一個(gè)Action實(shí)例和一個(gè)值棧對(duì)象浩螺。

因此:值棧的生命周期靴患,就是request生命周期。值棧要出、action鸳君、request生命周期一樣,不存在線程問題患蹂!
重定向跳轉(zhuǎn)頁面時(shí)或颊,目標(biāo)頁面無法獲取到Action中放入值棧的值。
4. 補(bǔ)充,通過EL表達(dá)式獲取值棧的值
EL 表達(dá)式原理:
 在page传于、request囱挑、session、application 四個(gè)范圍沼溜,調(diào)用getAttribute 獲取數(shù)據(jù)平挑。為什么也可以獲取值棧的值呢?

原因:Struts2提供StrutsRequestWrapper包裝類,對(duì)request 的 getAttribute 方法增強(qiáng) 通熄。
它優(yōu)先使用 request.getAttribute取值唆涝,如果取不到,執(zhí)行 valueStack的findValue方法使用值棧的默認(rèn)查找機(jī)制唇辨。

問題思考 : 
后臺(tái)代碼:
request.setAttribute(“name“, ”aaa“ ) ;//存入request域中
valueStack.set(“name“廊酣,”bbb“ )//存入值棧
頁面代碼:
<s:property name=”name” />   -----  值棧默認(rèn)查找機(jī)制,bbb
${name} ------ 優(yōu)先從request中查找,aaa 

四助泽、CRM案例:添加,顯示,修改客戶

1. 搭建環(huán)境

1.1 搭建Struts2環(huán)境
  • 拷貝前端頁面
  • 導(dǎo)入Struts2的jar包
  • 配置web.xml的前端控制器
  • 配置struts.xml文件
  • Struts2環(huán)境搭建完成
1.2 搭建Hibernate環(huán)境
  • 導(dǎo)入Hibernate的jar包

    • required包下的所有jar包
    • c3p0的jar包
    • 另,log4j-1.x的jar包
  • 刪除Struts2與Hibernate沖突的jar包

  • R : 數(shù)據(jù)庫表的編寫

  • O : 持久化類的編寫

  • M : 映射文件的編寫

  • 導(dǎo)入日志log4l.properties配置文件,創(chuàng)建核心配置文件hibernate.cfg.xml

  • 準(zhǔn)備工具類HibernateUtils

  • 創(chuàng)建包結(jié)構(gòu),測試Hibernate是否搭建成功

  • Hibernate搭建完成

2. 代碼實(shí)現(xiàn)功能

2.1 修改menu.jsp
新增客戶 : 跳轉(zhuǎn)到增加新客戶的頁面
    href="${pageContext.request.contextPath }/jsp/customer/add.jsp"

客戶列表 : 查詢所有客戶
    href="${pageContext.request.contextPath }/customer_list.action"
2.2 修改add.jsp
form 表單提交路徑 : 
    action="${pageContext.request.contextPath }/customer_save.action"
2.3 struts.xml請(qǐng)求與Action的配置關(guān)系
<struts>
    <constant name="struts.devMode" value="true" />
    <!-- 簡單樣式 -->
    <constant name="struts.ui.theme" value="simple"/>

    <package name="default" namespace="/" extends="struts-default">
        <action name="customer_*" class="com.itdream.crm.web.action.CustomerAction" method="{1}">
            <result name="flushListCustomer" type="redirectAction">customer_list.action</result>
            <result name="listCustomer">/jsp/customer/list.jsp</result>
            <!-- 默認(rèn)轉(zhuǎn)發(fā),傳遞customer數(shù)據(jù) -->
            <result name="editjsp">/jsp/customer/edit.jsp</result>
        </action>
    </package>
</struts>
2.4 Action動(dòng)作類處理請(qǐng)求
1. 提供模型驅(qū)動(dòng),用以封裝參數(shù)啰扛。
2. 查詢到的數(shù)據(jù),存入值棧轉(zhuǎn)發(fā)。
3. 下面是三個(gè)功能:新增客戶,查詢所有客戶,修改客戶

public class CustomerAction extends ActionSupport implements ModelDriven<Customer>{

    //提供模型對(duì)象
    private Customer customer = new Customer();
    
    @Override
    //Struts2獲取模型對(duì)象封裝
    public Customer getModel() {
        return customer;
    }
    
    //添加客戶
    public String save() {
        //獲取參數(shù),模型驅(qū)動(dòng)自動(dòng)封裝
        //調(diào)用業(yè)務(wù)層
        CustomerService service = new CustomerServiceImpl();
        service.addCustomer(customer);
        
        return "flushListCustomer";
    }
    
    //查詢所有客戶
    public String list() {
        //調(diào)用業(yè)務(wù)層
        CustomerService service = new CustomerServiceImpl();
        List<Customer> listCustomer = service.findListCustomer();
        
        //將所有Customer的數(shù)據(jù)存入值棧,以set方式存入Root棧
        ValueStack valueStack = ActionContext.getContext().getValueStack();
        valueStack.set("list", listCustomer);;
        //跳轉(zhuǎn)頁面
        return "listCustomer";
    }
    
    //查詢要修改的客戶,并跳轉(zhuǎn)到修改頁面
    public String showEdit() {
        //獲取參數(shù)
        Long cust_id = customer.getCust_id();
        //調(diào)用Service層
        CustomerService service = new CustomerServiceImpl();
        Customer customer2 = service.findCustomerById(cust_id);
        //將查詢到的客戶數(shù)據(jù)壓入值棧
        ActionContext.getContext().getValueStack().set("customer", customer2);
        //跳轉(zhuǎn)頁面
        return "editjsp";
    }

    //修改客戶信息
    public String update() {
        //獲取參數(shù)(模型驅(qū)動(dòng))
        //調(diào)用業(yè)務(wù)層
        System.out.println("hehe");
        CustomerService service = new CustomerServiceImpl();
         service.updateCustomer(customer);
        //跳轉(zhuǎn)
        return "flushListCustomer";
    }
}
2.5 Service層處理業(yè)務(wù)邏輯
public class CustomerServiceImpl implements CustomerService {

    @Override
    // 添加客戶
    public void addCustomer(Customer customer) {
        // 獲取Session對(duì)象
        Session session = HibernateUtils.getCurrentSession();
        // 開啟事務(wù)
        Transaction transaction = session.beginTransaction();
        // 業(yè)務(wù)邏輯
        try {
            CustomerDAO dao = new CustomerDAOImpl();
            dao.addCustomer(customer);
        } catch (Exception e) {
            // struts2默認(rèn)異澄撕兀回滾事務(wù),可以不寫
            transaction.rollback();
            e.printStackTrace();
        } finally {
            // 無論是否異常都提交事務(wù)結(jié)束事務(wù)
            transaction.commit();
        }
    }

    @Override
    // 查詢所有客戶
    public List<Customer> findListCustomer() {
        // 獲取Session對(duì)象
        Session session = HibernateUtils.getCurrentSession();
        // 開啟事務(wù)
        Transaction transaction = session.beginTransaction();
        // 業(yè)務(wù)邏輯
        List<Customer> listCustomer = null;
        try {
            CustomerDAO dao = new CustomerDAOImpl();
            listCustomer = dao.findListCustomer();
        } catch (Exception e) {
            // struts2默認(rèn)異骋猓回滾事務(wù),可以不寫
            transaction.rollback();
            e.printStackTrace();
        } finally {
            // 無論是否異常都提交事務(wù)結(jié)束事務(wù)
            transaction.commit();
        }
        return listCustomer;
    }

    @Override
    // 通過id查找客戶
    public Customer findCustomerById(Long cust_id) {
        // 獲取Session對(duì)象
        Session session = HibernateUtils.getCurrentSession();
        // 開啟事務(wù)
        Transaction transaction = session.beginTransaction();

        // 業(yè)務(wù)邏輯
        Customer customer = null;
        try {
            CustomerDAO dao = new CustomerDAOImpl();
            customer = dao.findCustomerById(cust_id);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            transaction.commit();
        }
        return customer;
    }

    @Override
    // 更新客戶信息
    public void updateCustomer(Customer customer) {
        // 獲取Session對(duì)象
        Session session = HibernateUtils.getCurrentSession();
        // 開啟事務(wù)
        Transaction transaction = session.beginTransaction();
        // 業(yè)務(wù)邏輯
        try {
            CustomerDAO dao = new CustomerDAOImpl();
            dao.updateCustomer(customer);
        } catch (Exception e) {
            // Struts2默認(rèn)異常回滾
            transaction.rollback();
            e.printStackTrace();
        } finally {
            // 提交事務(wù)
            transaction.commit();
        }
    }
}
2.6 dao層操作數(shù)據(jù)庫
1. 添加客戶需要先找到其關(guān)聯(lián)的聯(lián)系人建立關(guān)系
2. 持久態(tài)的使用

public class CustomerDAOImpl implements CustomerDAO {

    @Override
    //添加客戶
    public void addCustomer(Customer customer) {
        //獲取Session對(duì)象
        Session session = HibernateUtils.getCurrentSession();
        //首先找到客戶的聯(lián)系人
        //創(chuàng)建Criteria查詢對(duì)象
        Criteria criteria = session.createCriteria(Linkman.class);
        //創(chuàng)建限制條件
        Criterion criterion = Restrictions.eq("lkm_name", customer.getCust_linkman());
        //添加限制條件
        criteria.add(criterion);
        //查詢聯(lián)系人
        Linkman linkman = (Linkman) criteria.uniqueResult();
        if(linkman == null) {
            linkman = new Linkman();
            linkman.setLkm_name(customer.getCust_linkman());
        }
        
        //保存客戶到數(shù)據(jù)庫
        //建立關(guān)系:客戶表達(dá)與聯(lián)系人的關(guān)系:一個(gè)客戶有多個(gè)聯(lián)系人
        customer.getLinkmans().add(linkman);
        //建立關(guān)系:聯(lián)系人表達(dá)與客戶的關(guān)系:一個(gè)聯(lián)系人對(duì)應(yīng)一個(gè)客戶
        linkman.setCustomer(customer);
        
        //將customer變?yōu)槌志脩B(tài),配置了級(jí)聯(lián),會(huì)自動(dòng)級(jí)聯(lián)將linkman也變?yōu)槌志脩B(tài)
        session.save(customer);
    }

    @Override
    //查詢所有客戶
    public List<Customer> findListCustomer() {
        //單表查詢使用Criteria查詢更方便
        //獲取Session對(duì)象
        Session session = HibernateUtils.getCurrentSession();
        //創(chuàng)建Criteria查詢對(duì)象
        Criteria criteria = session.createCriteria(Customer.class);
        //執(zhí)行查詢
        return criteria.list();
    }

    @Override
    //通過ID查詢客戶
    public Customer findCustomerById(Long cust_id) {
        //獲取Session
        Session session = HibernateUtils.getCurrentSession();
        //get方法獲取的Customer已經(jīng)是持久態(tài)無需保存
        return session.get(Customer.class, cust_id);
    }

    @Override
    //更新客戶信息
    public void updateCustomer(Customer customer) {
        //獲取Session對(duì)象
        Session session = HibernateUtils.getCurrentSession();
        //修改客戶
        session.update(customer);
    }
}
2.7 顯示所有客戶list.jsp獲取值棧數(shù)據(jù)
<!-- 神奇的request先從request中找,找不到就走值棧的默認(rèn)查找機(jī)制,因此也能查找到存入值棧的list -->
<c:forEach items="${list }" var="customer">
    <TR style="FONT-WEIGHT: normal; FONT-STYLE: normal; BACKGROUND-COLOR: white; TEXT-DECORATION: none">
    <TD>${customer.cust_name }</TD>
    <TD>${customer.cust_level }</TD>
    <TD>${customer.cust_source }</TD>
    <TD>${customer.cust_linkman }</TD>
    <TD>${customer.cust_phone }</TD>
    <TD>${customer.cust_mobile }</TD>
    <TD>
    <a href="${pageContext.request.contextPath }/customer_showEdit.action?cust_id=${customer.cust_id}">修改</a>
    </TD>
2.8 edit.jsp獲取存入值棧的客戶信息,提交修改
form表單action請(qǐng)求地址:
    action="${pageContext.request.contextPath }/customer_update.action"

//隱藏域提交客戶id,從而找到該客戶進(jìn)行數(shù)據(jù)更新
<s:textfield name="cust_id" value="%{customer.cust_id}" type="hidden" />

客戶名稱:<s:textfield name="cust_name" value="%{customer.cust_name}" />
客戶級(jí)別:<s:textfield name="cust_level" value="%{customer.cust_level}" />
信息來源:<s:textfield name="cust_source" value="%{customer.cust_source}" />
聯(lián)系人:<s:textfield name="cust_linkman" value="%{customer.cust_linkman}" />
固定電話 :<s:textfield name="cust_phone" value="%{customer.cust_phone}" />
移動(dòng)電話 :<s:textfield name="cust_mobile" value="%{customer.cust_mobile}" />
2.9 功能完成,測試

結(jié)果圖:

img17.png
img18.png
img19.png
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末诫睬,一起剝皮案震驚了整個(gè)濱河市煞茫,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌摄凡,老刑警劉巖续徽,帶你破解...
    沈念sama閱讀 222,252評(píng)論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異亲澡,居然都是意外死亡钦扭,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,886評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門床绪,熙熙樓的掌柜王于貴愁眉苦臉地迎上來客情,“玉大人,你說我怎么就攤上這事癞己“蛘” “怎么了?”我有些...
    開封第一講書人閱讀 168,814評(píng)論 0 361
  • 文/不壞的土叔 我叫張陵痹雅,是天一觀的道長仰担。 經(jīng)常有香客問我,道長绩社,這世上最難降的妖魔是什么摔蓝? 我笑而不...
    開封第一講書人閱讀 59,869評(píng)論 1 299
  • 正文 為了忘掉前任,我火速辦了婚禮愉耙,結(jié)果婚禮上贮尉,老公的妹妹穿的比我還像新娘。我一直安慰自己劲阎,他們只是感情好绘盟,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,888評(píng)論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般龄毡。 火紅的嫁衣襯著肌膚如雪吠卷。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,475評(píng)論 1 312
  • 那天沦零,我揣著相機(jī)與錄音祭隔,去河邊找鬼。 笑死路操,一個(gè)胖子當(dāng)著我的面吹牛疾渴,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播屯仗,決...
    沈念sama閱讀 41,010評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼搞坝,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了魁袜?” 一聲冷哼從身側(cè)響起桩撮,我...
    開封第一講書人閱讀 39,924評(píng)論 0 277
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎峰弹,沒想到半個(gè)月后店量,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,469評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡鞠呈,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,552評(píng)論 3 342
  • 正文 我和宋清朗相戀三年融师,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片蚁吝。...
    茶點(diǎn)故事閱讀 40,680評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡旱爆,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出灭将,到底是詐尸還是另有隱情疼鸟,我是刑警寧澤后控,帶...
    沈念sama閱讀 36,362評(píng)論 5 351
  • 正文 年R本政府宣布庙曙,位于F島的核電站,受9級(jí)特大地震影響浩淘,放射性物質(zhì)發(fā)生泄漏捌朴。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,037評(píng)論 3 335
  • 文/蒙蒙 一张抄、第九天 我趴在偏房一處隱蔽的房頂上張望砂蔽。 院中可真熱鬧,春花似錦署惯、人聲如沸左驾。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,519評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽诡右。三九已至安岂,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間帆吻,已是汗流浹背域那。 一陣腳步聲響...
    開封第一講書人閱讀 33,621評(píng)論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留猜煮,地道東北人次员。 一個(gè)月前我還...
    沈念sama閱讀 49,099評(píng)論 3 378
  • 正文 我出身青樓,卻偏偏與公主長得像王带,于是被迫代替她去往敵國和親淑蔚。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,691評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容

  • 概述 什么是Struts2的框架Struts2是Struts1的下一代產(chǎn)品愕撰,是在 struts1和WebWork的...
    inke閱讀 2,263評(píng)論 0 50
  • 本文包括:1束倍、OGNL 表達(dá)式概述(了解)2、值棧概述3盟戏、值棧的存值與取值4绪妹、EL 表達(dá)式也會(huì)獲取到值棧中的數(shù)據(jù)5...
    廖少少閱讀 1,249評(píng)論 0 14
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法,類相關(guān)的語法柿究,內(nèi)部類的語法邮旷,繼承相關(guān)的語法,異常的語法蝇摸,線程的語...
    子非魚_t_閱讀 31,664評(píng)論 18 399
  • (一)Struts险毁、Spring、Hibernate们童、Mybatis框技術(shù) 1.Struts2.0有幾種標(biāo)簽庫 【...
    獨(dú)云閱讀 3,247評(píng)論 0 62
  • 人生的最終目的不一定是錢畔况,但是沒有錢卻是萬萬不行。我們的主業(yè)給我們帶來了穩(wěn)定的現(xiàn)金流慧库,因此跷跪,我們一定要珍惜自己的主...
    看世間濤走云飛閱讀 194評(píng)論 0 0