SSH綜合練習-第1天

SSH綜合練習-倉庫管理系統-第一天 javascript

 

綜合練習的總體目的css

整合應用 Struts2 、Hibernate、Spring 、Mysql 、 jQuery Ajax、java基礎知識html

  1. 熟悉企業SSH 基礎架構
  2. 掌握在SSH基礎架構 進行CRUD 編寫(抽取代碼) (單表、多表 )
  3. JQuery Ajax 編程實現(struts2整合json的插件包)

 

今天的主要內容: java

  1. 開發前的準備工做(原型導入、需求功能分析)
  2. 開發基礎環境的搭建(SSH環境搭建、MyEclipse逆向生成實體類和映射)
  3. 登陸功能的實現(三層架構搭建、通用代碼抽取、基於泛型的通用DAO
  4. 倉庫管理功能的實現(單表的CRUD、值棧的使用、其餘代碼抽取)
  5. 貨物管理功能的實現-入庫(倉庫列表的AJAX請求Spring和Ehcache緩存集成

 

  1. 開發前的準備工做

    1. 原型(靜態頁面)導入

原型就是軟件的一個早期可運行的版本,它實現了目標系統的某些功能,主要用於和用戶肯定其明確的需求。以及開發編碼的基礎頁面。mysql

原型:低精度+高精度jquery

  • 低精度:原型頁面粗糙,只是功能演示,不能做爲開發使用。功能參考。
  • 高精度:原型頁面精美,達到未來產品的效果。能夠做爲開發使用。

咱們這裏提供的原型就是倉庫管理系統靜態頁面的工程。web

【思考】ajax

如何導入原型工程?spring

  • 開發工具自動導入
  • 手動分類導入-推薦

 

新建Web項目storemanager:sql

 

導入靜態頁面和源碼配置等:

頁面賦值到WebRoot,源碼和配置複製到src

【提示】

複製的時候,不要覆蓋WEB-INF和META-INF目錄。

 

【部署測試】

將工程部署到tomcat中,啓動服務器,查看是否正常能訪問。

 

  1. 需求功能分析

詳細功能能夠參考需求文檔,也能夠查看原型來了解。

要開發的功能以下:

  • 登陸功能 (搭建項目基礎架構 ) ---- userinfo用戶表
  • 倉庫管理 (倉庫信息增刪改查) ----- store倉庫表
  • 貨物進出庫 (貨物的存入倉庫、 離開倉庫 ) ---- goods貨物表
  • 庫存管理 (查看倉庫中貨物狀況-盤點 )
  • 歷史記錄查詢 (將貨物進出庫進行記錄操做 )---- history 歷史記錄表

數據表:

表之間的關係:

表之間的關係:

用戶表:userinfo表,獨立

表名(中文)

表名(英文)

 

用戶表

userinfo

 

序號

字段名

類型

長度

NULL

說明

1

id

varchar

32

no

主鍵ID    

2

name

varchar

50

yes

用戶名

3

password

varchar

32

yes

密碼

 

倉庫表:store

1----- * 貨物goods (一個倉庫 能夠存放多種貨物 )

表名(中文)

表名(英文)

 

倉庫表

store

 

序號

字段名

類型

長度

NULL

說明

1

id

varchar

32

no

主鍵ID    

2

name

varchar

32

yes

倉庫名稱

3

addr

varchar

100

yes

倉庫地址

4

Manager

varchar

32

yes

倉庫管理員

 

貨物表:goods

1 ---- * 歷史記錄history (一種貨物,可能出入庫屢次,每次操做都要記錄歷史 )

表名(中文)

表名(英文)

 

貨物表

goods

 

序號

字段名

類型

長度

NULL

說明

1

id

varchar

32

no

主鍵ID    

2

name

varchar

50

yes

貨物名稱

3

nm

varchar

10

yes

簡記碼

4

unit

varchar

10

yes

計量單位

5

amount

double

 

yes

出/入庫數量

6

storeid

varchar

32

yes

倉庫id,對應倉庫表主鍵

 

歷史記錄表:history

表名(中文)

表名(英文)

 

歷史記錄表

history

 

序號

字段名

類型

長度

NULL

說明

1

id

varchar

32

no

主鍵ID    

2

goodsid

varchar

32

yes

貨物id,對應貨物表主鍵

2

datetime

varchar

19

yes

操做時間(當前時間)

3

_type

varchar

1

yes

出/入庫標識,1入庫,2出庫

4

amount

double

 

yes

本次出/入庫數量

5

remain

double

 

yes

餘量

6

_user

varchar

50

yes

操做人(Session中獲取),直接保存名稱,不引用userinfo表

 

 

 

  1. 數據庫生成

 

Mysql:

使用一個用戶,建一個數據庫,將腳本在該數據庫上運行,創建相應的表。

 

步驟:

 

  1. 新建用戶store

在Add User頁面中,用戶名和密碼都是store

  1. 新建數據庫itcaststore

  1. 給store用戶賦予itcaststore數據庫的相應的權限(全部權限)

  2. 從新使用store用戶登陸

登陸以後:

 

  1. 選中數據庫itcaststore,將sql\mysql\store.sql腳本粘貼過來,執行:建立4張表。

     

     

    create table userinfo( /*用戶表*/

    id varchar(32) primary key,

    name varchar(50),/*登陸名*/

    password varchar(32)/*密碼*/

    );

    /*倉庫表*/

    create table store(

        id varchar(32) primary key,

        name varchar(32),/*倉庫名稱*/

        addr varchar(100),/*倉庫所在地*/

        manager varchar(32) /*倉庫管理人員,不關聯userinfo表*/

    );

     

    /*貨物表*/

    create table goods(

        id varchar(32) primary key,

        name varchar(50),/*貨物名稱*/

        nm varchar(10),/*貨物簡記內碼,如阿斯匹林爲ASPL*/

        unit varchar(10), /*計量單位,1:個,2:GK,3:只,..*/

        amount numeric(10,2),/*庫存數量*/

        storeid varchar(32),/*所在倉庫ID*/

        constraint foreign key(storeid) references store(id)

    );

    /*出入庫歷史記錄*/

    create table history(

        id varchar(32) primary key,

        goodsid varchar(32),/*貨物ID*/

        datetime varchar(19),/*出入庫時間*/

        _type char(1),/*類型1:入庫,2:出庫*/

        amount numeric(10,2),/*此次出入庫的數量*/

        remain numeric(10,2),/*餘量*/

        _user varchar(50), /*操做員名稱,直接保存名稱,不引用userinfo表*/

        constraint foreign key(goodsid) references goods(id)

    );

 

  1. 開發基礎環境的搭建(SSH環境搭建、MyEclipse逆向生成實體類和映射)

技術選型:要用什麼技術組件(ssh+mysql)

  1. SSH開發環境構建

方式:引入ssh的jar和相關配置(web.xml和一些核心配置文件)

參考:須要的材料:課前資料中的

 

第一步:導入jar包。

 

第二步:導入web.xml(struts的過濾器和spring的監聽器):

能夠直接覆蓋WEB-INF

<?xml version="1.0" encoding="UTF-8"?>

<web-app version="2.5"

    xmlns="http://java.sun.com/xml/ns/javaee"

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee

    http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">

    <display-name></display-name>

    <!-- Spring ServletContextListener -->

    <listener>

        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>

    </listener>

 

    <!-- 加載配置文件默認 WEB-INF/applicationContext.xml -->

    <context-param>

        <param-name>contextConfigLocation</param-name>

        <param-value>classpath:applicationContext.xml</param-value>

    </context-param>

 

    <!-- Struts2 核心 過濾器 -->

    <filter>

        <filter-name>struts2</filter-name>

        <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class>

    </filter>

    <filter-mapping>

        <filter-name>struts2</filter-name>

        <url-pattern>/*</url-pattern>

    </filter-mapping>

 

    <welcome-file-list>

        <welcome-file>index.jsp</welcome-file>

    </welcome-file-list>

</web-app>

 

第三步:導入配置文件:

一般實際項目開發時 : "項目源碼、測試代碼、配置文件" 通常是分開的,因此咱們首先來規劃一下源碼文件夾。

新建源碼文件夾:

命名爲resource(用來存放資源文件)

命名爲test(用來存放測試文件)

咱們能夠新建不一樣功能的源代碼文件夾:

將配置文件都複製到resources。

 

最終結果:

其中:

  1. db.properties文件:

    jdbc.driverClass = com.mysql.jdbc.Driver

    jdbc.url = jdbc:mysql:///itcaststore

    jdbc.username = store

    jdbc.password = store

  2. log4j.properties文件

    ### direct log messages to stdout ###

    log4j.appender.stdout=org.apache.log4j.ConsoleAppender

    log4j.appender.stdout.Target=System.out

    log4j.appender.stdout.layout=org.apache.log4j.PatternLayout

    log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n

     

    ### direct messages to file mylog.log ###

    log4j.appender.file=org.apache.log4j.FileAppender

    log4j.appender.file.File=c:/mylog.log

    log4j.appender.file.layout=org.apache.log4j.PatternLayout

    log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n

     

    ### set log levels - for more verbose logging change 'info' to 'debug' ###

     

    log4j.rootLogger=info, stdout

     

  3. messages.properties

    國際化資源文件:用來實現項目的國際化

  4. struts.xml

    <?xml version="1.0" encoding="UTF-8" ?>

    <!DOCTYPE struts PUBLIC

        "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"

        "http://struts.apache.org/dtds/struts-2.3.dtd">

     

    <struts>

        <!--

            開發者模式:關閉:反作用:若是是ajax請求的狀況下,一旦出錯,不會在頁面上打印錯誤

            因此採用struts.i18n.reload和struts.configuration.xml.reload的模式

        -->

    <!-- <constant name="struts.devMode" value="true" /> -->

    <!-- 不用重啓服務器 -->

        <constant name="struts.i18n.reload" value="true" />

        <constant name="struts.configuration.xml.reload" value="true" />

        <!-- 表單樣式 -->

        <constant name="struts.ui.theme" value="simple" />

        <!-- 加載src下的國際化文件messages.properties -->

        <constant name="struts.custom.i18n.resources" value="messages" />

     

    <package name="default" namespace="/" extends="struts-default">

     

    </package>

     

    </struts>

    (5)applicationContext.xml文件

    <?xml version="1.0" encoding="UTF-8"?>

    <beans xmlns="http://www.springframework.org/schema/beans"

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xmlns:p="http://www.springframework.org/schema/p"

    xmlns:context="http://www.springframework.org/schema/context"

    xmlns:aop="http://www.springframework.org/schema/aop"

    xmlns:tx="http://www.springframework.org/schema/tx"

    xmlns:cache="http://www.springframework.org/schema/cache"

    xsi:schemaLocation="http://www.springframework.org/schema/beans

    http://www.springframework.org/schema/beans/spring-beans.xsd

    http://www.springframework.org/schema/context

    http://www.springframework.org/schema/context/spring-context.xsd

    http://www.springframework.org/schema/aop

    http://www.springframework.org/schema/aop/spring-aop.xsd

    http://www.springframework.org/schema/tx

    http://www.springframework.org/schema/tx/spring-tx.xsd

    http://www.springframework.org/schema/cache

    http://www.springframework.org/schema/cache/spring-cache.xsd">

        <!-- 引入外部屬性文件 -->

        <context:property-placeholder location="classpath:db.properties" />

     

        <!-- 鏈接池 -->

        <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">

            <property name="driverClass" value="${jdbc.driverClass}" />

            <property name="jdbcUrl" value="${jdbc.url}" />

            <property name="user" value="${jdbc.username}" />

            <property name="password" value="${jdbc.password}" />

        </bean>

     

        <!-- sessionFactory -->

        <bean id="sessionFactory"

            class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">

            <!-- 第一部分: 鏈接池 -->

            <property name="dataSource" ref="dataSource" />

            <!-- 第二部分: hibernate經常使用屬性 -->

            <property name="hibernateProperties">

                <props>

                    <prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>

                    <prop key="hibernate.hbm2ddl.auto">update</prop>

                    <prop key="hibernate.show_sql">true</prop>

                    <prop key="hibernate.format_sql">true</prop>

                </props>

            </property>

            <!-- 第三部分: 引入hbm -->

            <!-- <property name="mappingResources">

                <list>

                    <value>cn/itcast/storemanager/domain/Goods.hbm.xml</value>

                    <value>cn/itcast/storemanager/domain/History.hbm.xml</value>

                    <value>cn/itcast/storemanager/domain/Store.hbm.xml</value>

                    <value>cn/itcast/storemanager/domain/Userinfo.hbm.xml</value>

                </list>

            </property> -->

            <!-- 能夠批量引入hbm

            支持通配符

             -->

            <property name="mappingLocations">

                <list>

                    <value>classpath:cn/itcast/storemanager/domain/*.hbm.xml</value>

                </list>

            </property>

        </bean>

        

        <!-- 配置事務 -->

        <!-- 配置事務管理器平臺 -->

        <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">

            <property name="sessionFactory" ref="sessionFactory" />

        </bean>

        <!-- 事務管理通知 -->

        <tx:advice id="txAdvice" transaction-manager="transactionManager">

            <tx:attributes>

                <tx:method name="save*" read-only="false"/>

                <tx:method name="update*" read-only="false"/>

                <tx:method name="delete*" read-only="false"/>

                <tx:method name="find*" read-only="true"/>

            </tx:attributes>

        </tx:advice>

        

        <!-- 切入點和切面 -->

        <aop:config>

            <aop:pointcut expression="bean(*Service)" id="txPointcut"/>

            <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>

        </aop:config>

        

    </beans>

    1. 使用myeclipse反向生成功能

    不建議在原來項目上生成 ,新建web 項目abcdefg,用來保存生成的po類和hbm。

    點擊:

    切換Database Explorer 視圖,

    新建數據庫鏈接

     

    選擇Myeclipse視圖,選擇abcdefg項目,對abcdefg項目添加hibernate支持

    選擇Hibernate的版本

     

    點擊下一步:選擇DB Driver

    選擇abcdefg項目,建立包cn.itcast.storemanager.domain用來存放持久化對象和配置文件。

     

    回到數據透視圖,選擇表,進行反轉生成

    配置選項

     

    注意:兩點:

  • 包名的問題,最好實際項目用的什麼包名,這裏就指定什麼包名。
  • xml配置的話必須選擇java類的選項

 

 

修改applicationContext.xml 引入hbm映射

<!-- 第三部分: 引入hbm -->

        <property name="mappingResources">

            <list>

                <value>cn/itcast/storemanager/domain/Goods.hbm.xml</value>

                <value>cn/itcast/storemanager/domain/History.hbm.xml</value>

                <value>cn/itcast/storemanager/domain/Store.hbm.xml</value>

                <value>cn/itcast/storemanager/domain/Userinfo.hbm.xml</value>

            </list>

        </property>

最後:測試實體類是否正常:

刪除數據庫表,重啓服務,看是否報錯和自動生成表。

 

【擴展知識】批量映射配置:

<!-- 能夠批量引入hbm

            支持通配符

         -->

        <property name="mappingLocations">

            <list>

                <value>classpath:cn/itcast/storemanager/domain/*.hbm.xml</value>

            </list>

        </property>

 

 

 

 

  1. 登陸功能的實現(三層架構搭建、通用代碼抽取、基於泛型的通用Dao)

【業務邏輯梳理】

    用戶在頁面輸入用戶和密碼 -----> 數據封裝model --->- 經過Service傳遞到Dao 查詢數據庫 ---> 返回Userinfo對象 ---->

若是正確,將登陸信息保存到session,

若是不正確,封裝ActionError 返回登陸頁面。

 

  1. 三層架構設計思想

 

 

創建相應的包:

  1. 修改登陸頁面表單

目標頁面:login.jsp

使用struts2 標籤,由於須要回顯功能,新增struts標籤的taglib:

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

修改原來的form:

<s:form name="loginForm" action="user_login" namespace="/" method="post" cssStyle="margin-top:250px;">

 

</s:form>

注意:struts2標籤使用的標準的html標籤,所以,屬性必須加雙引號。

 

修改其餘標籤:

用戶名:<s:textfield name="name" cssClass="tx" maxLength="15" size="15" />

密碼:<s:password name="password" cssClass="tx" maxLength="15" size="15"/>

增長驗證信息顯示標籤:

<TR>

    <TD align="center" colSpan=3 width="623" height="260"

        background="<c:url value='/picture/welcome_01.gif'/>">

        <!-- 驗證碼返回提示 --> <br> <br> <br> <br> <br>

        <font color="#ff60a0" size="5">

            <!-- 回顯錯誤表單信息:表單校驗錯誤,針對具體字段 -->

            <s:fielderror></s:fielderror>

            <!-- 回顯通常錯誤信息 -->

            <s:actionerror/>

        </font>

    </TD>

</TR>

 

驗證修改的頁面是否存在錯誤:

在瀏覽器中刷新頁面查看。

 

  1. 編寫UserAction (表現層 )

簡化抽取Action類,讓Action類繼承BaseAction:

優點:

(1)使得全部Action都繼承ActionSupport。

(2)實現模型驅動的接口所有放置到BaseAction類中完成。

(3)將Action傳遞值的操做封裝到BaseAction中完成

 

第一步:在cn.itcast.storemanager.web.action中建立BaseAction的類:代碼:

//action的父類:用來存放action的重複代碼的

//通用:泛型

public abstract class BaseAction<T> extends ActionSupport implements ModelDriven<T>{

    //實例化數據模型T,模型驅動必須實例化

//    private T t = new T();

    //子類可見

    protected T model;//沒有初始化

 

    public T getModel() {

        return model;

    }

    

    //在默認的構造器初始化數據模型

    public BaseAction() {

        //在子類初始化的時候,默認會調用父類的構造器

        //反射機制:獲取具體的類型

        //獲得帶有泛型的類型,如BaseAction<Userinfo>

        Type superclass = this.getClass().getGenericSuperclass();

        //轉換爲參數化類型

        ParameterizedType parameterizedType = (ParameterizedType) superclass;

        //獲取泛型的第一個參數的類型類,如Userinfo

        Class<T> modelClass = (Class<T>) parameterizedType.getActualTypeArguments()[0];

        

        //實例化數據模型類型

        try {

            model = modelClass.newInstance();

        } catch (InstantiationException e) {

            e.printStackTrace();

        } catch (IllegalAccessException e) {

            e.printStackTrace();

        }

 

    }

    

    //封裝值棧的操做的方法

    //root棧:棧頂map,能夠經過key獲取value

    protected void setToValueStackRoot(String key,Object value){

        ActionContext.getContext().getValueStack().set(key, value);

    }

    

    //root棧:棧頂對象(匿名)

    protected void pushToValueStackRoot(Object value){

        ActionContext.getContext().getValueStack().push(value);

    }

    //map棧:--推薦,能夠經過key獲取value

    protected void putToValueStackMap(String key,Object value){

        ActionContext.getContext().put(key, value);

    }

    

    //root棧:action的屬性

    protected Object result;

    public Object getResult() {//action在root棧,所以,result也在root棧

        return result;

    }

}

 

 

第二步:建立UserAction子類代碼:用來接收頁面傳遞的user_login

//用戶操做的action

//public class UserAction extends ActionSupport implements ModelDriven<Userinfo>{

public class UserAction extends BaseAction<Userinfo>{

//    //數據模型對象,在BaseAction中體現

//    private Userinfo userinfo = new Userinfo();

//    @Override

//    public Userinfo getModel() {

//        return userinfo;

//    }

    

    //注入service

    private IUserService userService;

 

    public void setUserService(IUserService userService) {

        this.userService = userService;

    }

 

    //業務方法:登陸

    public String login(){

        System.out.println("用戶開始登陸了。。。。"+model);

        //調用業務層,查詢

        Userinfo loginUser= userService.login(model);

        if(loginUser == null){

            //登陸失敗

            //將失敗信息打印頁面

            addActionError(this.getText("UserAction.loginerror"));

            //跳轉到登陸

            return "loginjsp";

            

        }else{

            //登陸成功

            //將登陸用戶放入session

//            ServletActionContext.getRequest().getSession().setAttribute("loginUser", loginUser);

            ServletUtils.setLoginUserToSession(loginUser);

            //代碼:能夠抽取到baseAction,也能夠抽取到工具類中

            //跳轉到主頁

            return SUCCESS;

        }

        

    }

 

}

 

簡單分析:

當子類實例化的時候,會將具體的類型來代替參數化父類的T,並自動執行父類的構造方法,經過反射機制,獲得具體的模型的實例。struts經過getModel獲得模型對象。

開發小技巧:

  1. 能夠先將代碼寫完再統一配置(由於配置的時候須要代碼)
  2. 代碼能夠從前日後寫(從頁面-->Action-->Service-->Dao),也能夠從後往前寫(先寫Dao,再寫Action和Service)。

 

第三步:在cn.itcast.storemanager.utils包中抽取工具類ServletUtils.java:

//操做servlet相關

public class ServletUtils {

    

    //登陸用戶的key

    private static final String LOGIN_USER="loginUser";//常量

    

    //將登錄了用戶放入session

    //知足登陸和退出

    public static void setLoginUserToSession(Userinfo loginUser){

//        ServletActionContext.getRequest().getSession().setAttribute("loginUser", loginUser);

        if(null==loginUser){

            //清除登陸用戶

            ServletActionContext.getRequest().getSession().removeAttribute(LOGIN_USER);

        }else{

            //放登陸用戶

            ServletActionContext.getRequest().getSession().setAttribute(LOGIN_USER, loginUser);

        }

    }

    //從session獲取登陸用戶信息

    public static Userinfo getLoginUserFromSession(){

//        return (Userinfo)ServletActionContext.getRequest().getSession().getAttribute("loginUser");

        Object o = ServletActionContext.getRequest().getSession().getAttribute(LOGIN_USER);

        return o == null?null:(Userinfo)o;

    }

 

}

 

 

 

 

  1. 編寫UserService (業務層 )

第一步:設計新增父類Service,用於存放未來可能抽取出來的代碼:

//業務層的父類:用來複用公用代碼

//抽象類

public abstract class BaseService {

 

}

第二步:編寫具體業務接口service

public interface IUserService {

 

    /**

     * 用戶登陸操做

     */

    Userinfo login(Userinfo userInfo);

 

}

第三步:編寫具體業務接口的實現類UserServiceImpl.java

//繼承BaseService:能夠代碼複用

//實現UserService:用來實現業務邏輯操做

public class UserServiceImpl extends BaseService implements IUserService {

 

    //注入dao

//    private UserDAO userDAO;

    //注入用戶操做的dao

    private IGenericDao<Userinfo, String> userDao;//具體類型的dao

    public void setUserDao(IGenericDao<Userinfo, String> userDao) {

        this.userDao = userDao;

    }

 

    //登陸驗證,使用用戶名和密碼做爲查詢條件,查詢對應的惟一對象,若是有存在則返回,不存在返回null

    public Userinfo login(Userinfo userInfo) {

        //調用dao

        //QBC

        //離線條件

        DetachedCriteria criteria =DetachedCriteria.forClass(Userinfo.class)

                .add(Restrictions.eq("name", userInfo.getName()))

                .add(Restrictions.eq("password", userInfo.getPassword()));

        List<Userinfo> list = userDao.findByCriteria(criteria);

        return list.isEmpty()?null:list.get(0);

    }

}

 

  1. 編寫GenericDao 通用Dao (數據層)

 

第一步:在cn.itcast.storemanager.daol包中,通用數據接口IGenericDao.java代碼:

//通用DAO接口:爲了簡化代碼開發

public interface IGenericDao<T,ID extends Serializable> {

    

    /**

     * 保存數據

     * @param domain

     */

    public void save(Object domain);

    

    /**

     * 更新

     * @param domain

     */

    public void update(Object domain);

    

    /**

     * 刪除

     * @param domain

     */

    public void delete(Object domain);

    

    /**

     * 根據id查詢對象

     * @param domainClass

     * @param id

     * @return

     */

    public T findById(Class<T> domainClass, ID id);

    

    /**

     * 查詢全部

     * @return

     */

    public List<T> findAll(Class<T> domainClass);

    

    //複雜條件查詢

    /**

     * 命名查詢

     * @param queryName

     * @param values

     * @return

     */

    public List<T> findByNamedQuery(String queryName, Object... values);

    

    /**

     * 離線條件查詢

     * @param criteria

     * @return

     */

    public List<T> findByCriteria(DetachedCriteria criteria);

    

 

}

第二步:在cn.itcast.storemanager.dao.impl包中通用數據接口實現類GenericDaoImpl.java代碼

//通用dao的實現

//hibernate模版類操做,繼承daosupport

public class GenericDaoImpl<T,ID extends Serializable> extends HibernateDaoSupport implements IGenericDao<T, ID> {

 

    

    //保存對象

    public void save(Object domain) {

        getHibernateTemplate().save(domain);

    }

 

    //修改對象

    public void update(Object domain) {

        getHibernateTemplate().update(domain);

    }

 

    //刪除對象

    public void delete(Object domain) {

        getHibernateTemplate().delete(domain);

    }

 

    

    //使用主鍵ID查詢

    public T findById(Class<T> domainClass, ID id) {

        return getHibernateTemplate().get(domainClass, id);

    }

 

    

    //查詢全部

    public List<T> findAll(Class<T> domainClass) {

        return getHibernateTemplate().loadAll(domainClass);

    }

 

    //命名查詢

    public List<T> findByNamedQuery(String queryName, Object... values) {

        return getHibernateTemplate().findByNamedQuery(queryName, values);

    }

 

    //QBC

    public List<T> findByCriteria(DetachedCriteria criteria) {

        return getHibernateTemplate().findByCriteria(criteria);

    }

 

}

開發小技巧:

  1. 抽取代碼的時候,也能夠從實現類往接口上抽取。
  2. 抽取代碼相對比較複雜一點,但只須要寫一次,就能夠供全部業務使用,說白了,就是實現了對通用方法的封裝,不用每次在不一樣的Dao中寫重複的代碼。

 

 

附加:若是開發中使用命名查詢,能夠在hbm文件中配置命名查詢語句 (Userinfo.hbm.xml)

<!-- 使用命名查詢 -->

<query name="Userinfo.login">

        from Userinfo where name = ? and password = ?

</query>

 

 

  1. 統一配置(struts.xml,message.properties,applicationContext.xml)

配置幾個:頁面跳轉、國際化、struts二、Spring核心配置文件。

第一步:配置 struts.xml

<?xml version="1.0" encoding="UTF-8" ?>

<!DOCTYPE struts PUBLIC

    "-//Apache Software Foundation//DTD Struts Configuration 2.3//EN"

    "http://struts.apache.org/dtds/struts-2.3.dtd">

 

<struts>

    <!--

        開發者模式:關閉:反作用:若是是ajax請求的狀況下,一旦出錯,不會在頁面上打印錯誤

        因此採用struts.i18n.reload和struts.configuration.xml.reload的模式

    -->

<!-- <constant name="struts.devMode" value="true" /> -->

<!-- 不用重啓服務器 -->

    <constant name="struts.i18n.reload" value="true" />

    <constant name="struts.configuration.xml.reload" value="true" />

    <!-- 表單樣式 -->

    <constant name="struts.ui.theme" value="simple" />

    <!-- 加載src下的國際化文件messages.properties -->

    <constant name="struts.custom.i18n.resources" value="messages" />

 

<package name="default" namespace="/" extends="struts-default">

        <!-- 用戶管理相關 -->

        <!-- <action name="user_*" class="cn.itcast.storemanager.web.action.UserAction" method="{1}"> -->

        <action name="user_*" class="userAction" method="{1}">

            <result name="loginjsp">/login.jsp</result>

            <result type="redirect">/jsps/main.jsp</result>

        </action>

</package>

 

</struts>

第二步:在src下配置messages.properties

UserAction.loginerror=\u60A8\u8F93\u5165\u7684\u7528\u6237\u540D\u6216\u5BC6\u7801\u4E0D\u6B63\u786E

顯示:

第三步:配置applicationContext.xml

(1)事務管理中增長login方法的事務控制:

<!-- 配置事務 -->

    <!-- 配置事務管理器平臺 -->

    <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">

        <property name="sessionFactory" ref="sessionFactory" />

    </bean>

    <!-- 事務管理通知 -->

    <tx:advice id="txAdvice" transaction-manager="transactionManager">

        <tx:attributes>

            <tx:method name="save*" read-only="false"/>

            <tx:method name="update*" read-only="false"/>

            <tx:method name="delete*" read-only="false"/>

            <tx:method name="find*" read-only="true"/>

            <tx:method name="login" read-only="true"/>

        </tx:attributes>

    </tx:advice>

    

    <!-- 切入點和切面 -->

    <aop:config>

        <aop:pointcut expression="bean(*Service)" id="txPointcut"/>

        <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/>

    </aop:config>

(2)三層的Bean配置:

<!--通用的DAO類 -->

    <bean id="userDao" class="cn.itcast.storemanager.dao.impl.GenericDaoImpl">

        <property name="sessionFactory" ref="sessionFactory"/>

    </bean>

    

    <!-- service -->

    <bean id="userService" class="cn.itcast.storemanager.service.impl.UserServiceImpl">

        <property name="userDao" ref="userDao"/>

    </bean>

    

    <!-- action -->

    <bean id="userAction" class="cn.itcast.storemanager.web.action.UserAction" scope="prototype">

        <property name="userService" ref="userService"/>

    </bean>

總體運行登陸測試:

在數據庫中新增用戶admin,密碼admin,登陸測試功能。

 

  1. 倉庫管理功能的實現(單表的CRUD)

分析:倉庫表不依賴於其餘表,是獨立的單表操做。下面咱們實現倉庫表的CRUD

爲了實現業務,咱們要編寫的內容:

  1. 倉庫添加功能

通常開發功能基本三步:

頁面---java代碼邏輯—配置文件

頁面:

第一步: 改造表單(/jsps/store/add.jsp):將頁面改造 <s:form>     

<s:form action="store_add" namespace="/" method="post" name="select">

 

</s:form>

 

<tr>

                            <td style="padding-left:10px;" colspan="2" align="left">

                                <font color="red">

                                    <s:fielderror/>

                                    <s:actionerror/>

                                </font>

                            </td>

                        </tr>

                        <tr>

                            <td>

                                倉庫名稱:

                            </td>

                            <td>

                                <s:textfield name="name" cssClass="tx"/>

                            </td>

                        </tr>

                        <tr>

                            <td>

                                倉庫地址:

                            </td>

                            <td>

                                <s:textfield name="addr" cssClass="tx"/>

                            </td>

                        </tr>

                        <tr>

                            <td>

                                庫管員:

                            </td>

                            <td>

                                <s:textfield name="manager" cssClass="tx"/>

                            </td>

                        </tr>

測試:

刷新頁面,看是否添加頁面顯示正常。

 

第二步: 編寫服務器端java代碼

編寫邏輯分析:咱們的目標是增刪改查:

  • 增長、刪除、修改 -----> 重定向查詢的Action
  • 查詢的Action(從新查詢數據) -----> 轉發列表jsp頁面

 

第三步:編寫StoreAction:

//倉庫管理的action

public class StoreAction extends BaseAction<Store>{

    //注入service

    private IStoreService storeService;

    public void setStoreService(IStoreService storeService) {

        this.storeService = storeService;

    }

 

 

    //保存倉庫

    @InputConfig(resultName="addInput")//用於指定input進行struts2的校驗

    public String add(){

        //業務層保存操做

        storeService.saveStore(model);

//        return "listjsp";//跳轉到列表

        return "storelist";//先查列表//使用重定向技術

    }

}

第四步:編寫IStoreService 接口

//倉庫的業務層接口

public interface IStoreService {

 

    /**

     * 保存倉庫

     * @param store

     */

    public void saveStore(Store store);

}

第五步:編寫StoreServiceImpl 代碼

//倉庫管理的業務層實現

public class StoreServiceImpl extends BaseService implements IStoreService{

    //注入dao

    private IGenericDao<Store, String> storeDao;

    public void setStoreDao(IGenericDao<Store, String> storeDao) {

        this.storeDao = storeDao;

    }

 

    

    //@CacheEvict(value="storemanager",allEntries=true)//清除緩存區域的全部對象

    public void saveStore(Store store) {

        storeDao.save(store);

    }

 

第六步: 配置struts.xml

<!-- 倉庫管理相關 -->

        <action name="store_*" class="storeAction" method="{1}">

            <!-- 列表頁面 -->

            <result name="listjsp">/jsps/store/store.jsp</result>

            <!-- 列表查詢action -->

            <result name="storelist" type="redirectAction">store_list</result>

            <!-- 添加倉庫 -->

            <result name="addInput">/jsps/store/add.jsp</result>

</action>

第七步:配置applicationContext.xml

<!--通用的DAO類 -->

    <bean id="userDao" class="cn.itcast.storemanager.dao.impl.GenericDaoImpl">

        <property name="sessionFactory" ref="sessionFactory"/>

    </bean>

    <bean id="storeDao" class="cn.itcast.storemanager.dao.impl.GenericDaoImpl">

        <property name="sessionFactory" ref="sessionFactory"/>

    </bean>

    

    <!-- service -->

    <bean id="userService" class="cn.itcast.storemanager.service.impl.UserServiceImpl">

        <property name="userDao" ref="userDao"/>

    </bean>

    <bean id="storeService" class="cn.itcast.storemanager.service.impl.StoreServiceImpl">

        <property name="storeDao" ref="storeDao"/>

    </bean>

    

    <!-- action -->

    <bean id="userAction" class="cn.itcast.storemanager.web.action.UserAction" scope="prototype">

        <property name="userService" ref="userService"/>

    </bean>

    <bean id="storeAction" class="cn.itcast.storemanager.web.action.StoreAction" scope="prototype">

        <property name="storeService" ref="storeService"/>

    </bean>

注意:Action是多例。

 

第八步:表單校驗

    局部校驗: Action所在包 "Action類名-<action>標籤name屬性-validation.xml"。

(1)新建xml文件:

引入配置文件頭部:

位置:xwork-core-2.3.15.3.jar中的xwork-validator-1.0.3.dtd中

詳細驗證規則能夠參考:

(2)配置:StoreAction-store_add-validation.xml

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE validators PUBLIC

        "-//Apache Struts//XWork Validator 1.0.3//EN"

        "http://struts.apache.org/dtds/xwork-validator-1.0.3.dtd">

        

<validators>

    <!-- 倉庫的名稱 -->

    <field name="name">

        <field-validator type="requiredstring">

            <message key="StoreAction.name.required"/>

        </field-validator>

    </field>

    <!-- 倉庫的地址 -->

    <field name="addr">

        <field-validator type="requiredstring">

            <message key="StoreAction.addr.required"/>

        </field-validator>

    </field>

    <!-- 倉庫的管理員 -->

    <field name="manager">

        <field-validator type="requiredstring">

            <message key="StoreAction.manager.required"/>

        </field-validator>

    </field>

 

</validators>

 

(2)修改messages.properties

UserAction.loginerror=\u60A8\u8F93\u5165\u7684\u7528\u6237\u540D\u6216\u5BC6\u7801\u4E0D\u6B63\u786E

StoreAction.name.required=\u4ED3\u5E93\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A

StoreAction.addr.required=\u4ED3\u5E93\u5730\u5740\u4E0D\u80FD\u4E3A\u7A7A

StoreAction.manager.required=\u4ED3\u5E93\u7684\u7BA1\u7406\u5458\u4E0D\u80FD\u4E3A\u7A7A

 

視圖查看:

 

(5)在add.jsp頁面中 添加 <s:fielderror> 回顯標籤。

<tr>

        <td style="padding-left:10px;" colspan="2" align="left">

            <font color="red">

                <s:fielderror/>

                <s:actionerror/>

            </font>

        </td>

</tr>

另外,還須要配置校驗錯誤的默認返回的input結果集。

<!-- 倉庫管理相關 -->

        <action name="store_*" class="storeAction" method="{1}">

            <!-- 列表頁面 -->

            <result name="storelist">/jsps/store/store.jsp</result>

            <!-- 列表查詢action -->

            <result name="listjsp" type="redirectAction">store_list</result>

            <!-- 添加倉庫 校驗出錯跳轉的頁面-->

            <result name="input">/jsps/store/add.jsp</result>

</action>

 

重啓服務進行測試:

分別不填寫和填寫倉庫信息,看是否能正常保存到數據庫。

添加一條數據,到數據庫查看是否存在。

 

  1. 倉庫列表查詢功能

流程:點擊查看倉庫 跳轉store_list.action 先查詢 到jsp顯示。

第一步:先修改左側導航菜單的連接:修改main.jsp

在main.jsp中引入struts2的標籤庫,將倉庫管理鏈接的普通標籤改成struts2標籤:

<s:a namespace="/" action="store_list.action" target="content" id="left1002">[倉庫管理]</s:a>

 

第二步:在StoreAction 添加 list查詢方法

//倉庫管理的action

public class StoreAction extends BaseAction<Store>{

    //注入service

    private IStoreService storeService;

    public void setStoreService(IStoreService storeService) {

        this.storeService = storeService;

    }

 

 

    //保存倉庫

    @InputConfig(resultName="addInput")//用於指定input進行struts2的校驗

    public String add(){

        //業務層保存操做

        storeService.saveStore(model);

//        return "listjsp";//跳轉到列表

        return "storelist";//先查列表

    }

    

    //列表查詢倉庫

    public String list(){

        List<Store> list = storeService.findAllStore();

        //list放入map

        putValueStackMap("list", list);

        //返回列表頁面

        return "storejsp";

    }

}

提示:記得將save的Action的返回結果修改回storelist。

 

第三步:修改IStoreService接口

/**

     * 查詢全部倉庫列表

     * @return

     */

    public List<Store> findAllStore();實現

第四步:修改StoreServiceImpl類

public List<Store> findAllStore() {

    return storeDao.findAll(Store.class);

}

 

 

修改列表頁面store.jsp來回顯數據

<tr style="background:#D2E9FF;text-align: center;">

    <td>名稱</td>

        <td>地址</td>

        <td>管理員</td>

        <td>操做</td>

</tr>

                                

<s:iterator value="#list" >                                    

<tr>

        <td><s:property value="name"/></td>

        <td><s:property value="addr"/></td>

        <td><s:property value="manager"/></td>

        <td>

            <s:a action="store_editview" namespace="/">

            <s:param name="id" value="id"/>

                    修改

            </s:a>

            <s:a action="store_delete" namespace="/" cssClass="delLink">

            <s:param name="id" value="id"/>

                    刪除

            </s:a>

        </td>        

    </tr>

</s:iterator>

 

重啓服務測試:

 

  1. 倉庫刪除功能

思路:根據主鍵id,拼接超連接來刪除:<a href="….?id=xxx"> 刪除 </a>

 

第一步:修改store.jsp 頁面刪除連接

<s:a action="store_delete" namespace="/" cssClass="delLink">

    <s:param name="id" value="id"/>

        刪除

</s:a>

第二步:在StoreAction 添加delete 方法

//刪除倉庫

    public String delete(){

        //調用業務層

        storeService.deleteStore(model);

        //返回到列表

        return "storelist";

    }

第三步:IStoreService接口 代碼

/**

     * 根據id刪除倉庫

     * @param store

     */

    public void deleteStore(Store store);

第四步:StoreServiceImpl類的代碼

    public void deleteStore(Store store) {

 

        storeDao.delete(store);

    }

 

 

第五步:重啓服務測試刪除。

 

【提示】:若是部分較舊的瀏覽器可能會報js錯誤,那麼換個較新的瀏覽器試試。

之後你們在開發過程當中,必定要注意瀏覽器的兼容性問題,在交付項目、上線以前,要用客戶的所用的瀏覽器測試一下。

 

【思考】:

若是倉庫中存在貨物,可否刪除 ???

可能沒法刪除,可能報錯!!

緣由是:有主外鍵關聯。

 

【功能優化】:

在頁面添加 JS確認刪除效果。

store.jsp

<s:a action="store_delete" onclick="return confirm('是否確認刪除')">

 

  1. 倉庫修改功能

分析修改,兩步:須要先查詢回顯數據,再進行修改提交

所以,功能開發須要分兩部分:表單回顯和更新提交。咱們分別來作。

 

第一部分:表單回顯(查詢)。

第一步:修改 store.jsp 修改超連接(參考刪除)

<s:a action="store_editview" namespace="/">

        <s:param name="id" value="id"/>

        修改

</s:a>

 

第二步:在StoreAction 添加 editview 方法

//修改的回顯

    public String editview(){

        //根據id查詢出來數據,壓入棧頂

        Store store=storeService.findStoreById(model.getId());

        pushToValueStackRoot(store);

        //跳轉到修改頁面

        return "editjsp";

    }

 

第三步:業務層IStoreServcie接口:

/**

     * 根據id查詢倉庫

     * @param id

     * @return

     */

    public Store findStoreById(String id);

 

第四步:業務層StoreServcieImpl:

public Store findStoreById(String id) {

        return storeDao.findById(Store.class, id);

    }

 

第五步:配置struts.xml 跳轉編輯頁面

<!-- 倉庫管理相關 -->

        <action name="store_*" class="storeAction" method="{1}">

            <!-- 列表頁面 -->

            <result name="listjsp">/jsps/store/store.jsp</result>

            <!-- 列表查詢action -->

            <result name="storelist" type="redirectAction">store_list</result>

            <!-- 添加倉庫 -->

            <result name="addInput">/jsps/store/add.jsp</result>

            <!-- 修改頁面 -->

            <result name="editjsp">/jsps/store/edit.jsp</result>

            <result name="editInput">/jsps/store/edit.jsp</result>

</action>

 

第六步:修改edit.jsp頁面, 將<form> 改造爲 <s:form>,使其擁有回顯功能。

<s:form action="store_edit" namespace="/" method="post" name="select">

 

</s:form>

思考:修改表單和添加表單的區別是什麼?

就差一個主鍵id。所以,修改須要隱藏一個id,用來傳遞id執行更新。

【補充】實際業務開發中,你能夠將保存和修改頁面用一個。(就根據判斷頁面有沒有傳過來id來判斷是修改仍是保存)-課外補充-回去試試。

<tr>

                <td bgcolor="a0c0c0" style="padding-left:10px;" colspan="2" align="left">

                    <b>修改新倉庫:</b>

                </td>

</tr>

                        <tr>

                            <td style="padding-left:10px;" colspan="2" align="left">

                                <font color="red">

                                    <s:fielderror/>

                                    <s:actionerror/>

                                </font>

                            </td>

                        </tr>

                        <tr>

                            <td>

                                倉庫名稱:

                            </td>

                            <td>

                                <s:textfield name="name" cssClass="tx"/>

                                <!-- id隱藏域 -->

                                <s:hidden name="id"/>

                            </td>

                        </tr>

                        <tr>

                            <td>

                                倉庫地址:

                            </td>

                            <td>

                                <s:textfield name="addr" cssClass="tx"/>

                            </td>

                        </tr>

                        <tr>

                            <td>

                                庫管員:

                            </td>

                            <td>

                                <s:textfield name="manager" cssClass="tx"/>

                            </td>

                        </tr>

第七步:回顯階段功能測試,測試點:

  • 查看修改頁面是否能數據填充回顯;
  • 用firebug等工具或者查看頁面源代碼查看id是否正常;

 

第二部分:數據更新提交。

第一步:在edit.jsp中編輯form表單

<s:form action="store_edit" namespace="/" method="post" name="select">

 

</s:form>

 

第二步:修改form 提交,StoreAction添加 edit方法

//修改倉庫數據

    @InputConfig(resultName="editInput")

    public String edit(){

        //將數據傳入業務層

        storeService.updateStore(model);

        //跳轉到列表頁面

        return "storelist";

        

    }

第三步:業務層IStoreService代碼

/**

     * 更新倉庫

     * @param store

     */

    public void updateStore(Store store);

第四步:業務層StoreServiceImpl.java

public void updateStore(Store store) {

        //hibernate自動根據id來修改全部字段的

        storeDao.update(store);

    }

提示:

這裏的修改直接調用update方法,得必須保證store的屬性都有值。

 

第五步:測試修改功能。

 

 

功能優化補充:增長表單校驗功能。

增長校驗文件:(將添加的校驗文件再複製一份,重命名爲)

頁面上增長:

<tr>

                            <td bgcolor="a0c0c0" style="padding-left:10px;" colspan="2" align="left">

                                <b>修改新倉庫:</b>

                            </td>

                        </tr>

                        <tr>

                            <td style="padding-left:10px;" colspan="2" align="left">

                                <font color="red">

                                    <s:fielderror/>

                                    <s:actionerror/>

                                </font>

                            </td>

                        </tr>

發現問題:

若是修改方法也添加了校驗, 默認跳轉input視圖, 但添加方法已經配置了input,怎麼辦?

解決辦法:修改默認input視圖,讓修改和添加的校驗失敗後分別跳到不一樣的input --------- @InputConfig,能夠經過resultName屬性指定不一樣input的名稱。

 

(1)修改storeAction,添加註解@InputConfig。

//保存倉庫

    @InputConfig(resultName="addInput")//用於指定input進行struts2的校驗

    public String add(){

        //業務層保存操做

        storeService.saveStore(model);

//        return "listjsp";//跳轉到列表

        return "storelist";//先查列表

    }

 

//修改倉庫數據

    @InputConfig(resultName="editInput")

    public String edit(){

        //將數據傳入業務層

        storeService.updateStore(model);

        //跳轉到列表頁面

        return "storelist";

        

    }

 

配置struts.xml,分別對增長和修改配置不一樣input視圖 。

<!-- 倉庫管理相關 -->

        <action name="store_*" class="storeAction" method="{1}">

            <!-- 列表頁面 -->

            <result name="listjsp">/jsps/store/store.jsp</result>

            <!-- 列表查詢action -->

            <result name="storelist" type="redirectAction">store_list</result>

            <!-- 添加倉庫 -->

            <result name="addInput">/jsps/store/add.jsp</result>

            <!-- 修改頁面 -->

            <result name="editjsp">/jsps/store/edit.jsp</result>

            <result name="editInput">/jsps/store/edit.jsp</result>

        </action>

再次測試校驗失敗的頁面跳轉功能。

 

 

 

  1. 貨物管理功能的實現-入庫(倉庫列表的AJAX請求,Spring和Ehcache緩存集成)

 

分析一下功能:

入庫主要是將貨物保存到倉庫中,那麼保存貨物是須要選擇倉庫的,所以,下面咱們在作入庫功能以前,先要實現倉庫列表的顯示。

 

 

  1. 倉庫列表查詢顯示

點擊【入庫】

 

【分析】

有兩種方案:

  1. 打開這個頁面的時候,在值棧中放入倉庫的列表對象,頁面使用ongl表達式,獲取到列表對象,讓下拉本身顯示數據

<!-- ongl表達式獲取列表(list中是不少map)將List<Store> 存放到map棧,命名爲storeList -->

<s:select list="#storeList" name="storeId" id="storeId" listKey="id" listValue="name"></s:select>

2.將下拉列表當作一個獨立組件,該組件的數據獨立加載,和外面的業務無關。

這裏採用第二種方式。

選擇倉庫列表,一般更多使用Ajax交互獲取

    異步交互:(json和xml) 最經常使用的數據格式 json ({key:value} 對象, [elements] 數組 )

 

第一步:在系統頁面 導入jQuery

    /jsps/save/save.jsp 入庫頁面

<!-- 引入jquery庫 -->

<script type="text/javascript" src="${pageContext.request.contextPath}/js/jquery-1.8.3.js"></script>

 

第二步: 基於一個事件,發生Ajax請求 :(這裏是頁面加載後填充列表數據---你們也可使用點擊事件)

Jquery Ajax 最經常使用的兩個操做 $.get 、$.post (若是有參數,則須要用post;沒有參數,則隨意,通常咱們都用post)

咱們這裏能夠省略請求參數和返回內容格式,只須要請求地址和回調函數便可,代碼以下:

<script type="text/javascript">

    $(function(){

        //頁面加載後,發生ajax請求

        /**

        url,[data],[callback],[type]String,Map,Function,String

        url:發送請求地址。

        data:待發送 Key/value 參數。請求的數據

        callback:發送成功時回調函數。

        type:返回內容格式,xml, html, script, json, text, _default

        */

        $.post("${pageContext.request.contextPath}/store_listAjax.action",function(data){

            //data是服務器返回的內容(本來是json字符串),通過轉換後的對象(js對象或js數據對象)。

            

            

        });

        

        

    });

    

</script>

 

第三步: 服務器處理數據,將處理結果生成json,返回客戶端。

分析:其實這個異步請求倉庫數據的方法與查詢全部倉庫數據的方法基本是一致的,只是返回結果不一樣。一個是返回List集合到跳轉頁面,一個是返回json字符串。

在StoreAction 添加 listAjax方法:

//查詢全部列表(給異步請求用的)

    public String listAjax(){

        

        return "listajax";    

}

     那麼如何將查詢結果轉換爲json?

可使用struts2提供json插件包(struts2-json-plugin.jar),完成值棧中數據,到json轉換返回。

 

    手動導入插件包:

 

 

查看 struts-plugin.xml(瞭解插件的基本做用)

    該插件編寫一個新的package (json-default) ,而且內部提供 json 結果集類型 ,只要使用json結果集類型,struts2 將數據轉換爲json格式返回客戶端 !

 

編寫StoreAction,將查詢的集合存放到root棧的result屬性中。

//查詢全部列表(給異步請求用的)

    public String listAjax(){

                //查詢全部倉庫,返回list

        List<Store> storeList = storeService.findAllStore();

        //怎樣讓list轉化成json?

        /**

         * 第一步: struts2-json-plugin-2.3.15.3.jar

         * 第二步:修改struts.xml配置:<package name="default" namespace="/" extends="json-default">

         * 第三步:修改struts.xml文件:添加返回值:<result name="listajax" type="json"></result>

         * 第四步:list壓入棧頂

         * */

        pushValueStackRoot(storeList);

        return "listajax";    

    }

 

在struts.xml 配置結果集:

更改默認包:(要求咱們的包去繼承json-default包)

<package name="default" namespace="/" extends="json-default">

 

</package>

思考:

咱們要將哪些數據轉換爲json?

分析一下JsonResult(org.apache.struts2.json.JSONResult) 源碼,關聯struts2源碼來查看(課件中的SSH整合原始包中有相應zip包):

====================================================================

轉換成json

    若是爲結果集配置root參數,去值棧找root參數值對應對象,轉換爲json返回,若是沒有配置root參數, 將root棧的頂部對象返回(默認model在棧頂,若是沒有model,則action在棧頂) !

struts.xml

<!-- 倉庫管理相關 -->

        <action name="store_*" class="storeAction" method="{1}">

            <!-- 列表頁面 -->

            <result name="listjsp">/jsps/store/store.jsp</result>

            <!-- 列表查詢action -->

            <result name="storelist" type="redirectAction">store_list</result>

            <!-- 添加倉庫 -->

            <result name="addInput">/jsps/store/add.jsp</result>

            <!-- 修改頁面 -->

            <result name="editjsp">/jsps/store/edit.jsp</result>

            <result name="editInput">/jsps/store/edit.jsp</result>

            

            <!-- json結果集類型 -->

            <result name="listajax" type="json">

            

            </result>

        </action>

 

測試調試:

經過firebug抓包工具查看數據是否返回 !

提示:若是配置的是開發者模式,則這裏會返回200,而不是錯誤500。

控制檯打印了異常:

Caused by: org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: cn.itcast.storemanager.domain.Store.goodses, no session or session was closed

緣由是:查詢store的時候,其集合屬性goods默認是延遲加載的,而store返回到表現層action的時候,事務已經在service層結束了,也說明鏈接和session關了。

思考:能夠用OpenSessionInView麼?

能夠解決報錯,但不合適,由於,咱們不須要goods關聯集合屬性的數據,只是須要store便可。性能會下降。

 

解決方案: 使用@JSON註解,排除不須要轉的屬性 --- 添加getXxx方法上:

在Store的po類上的getGoodses上添加註解:表示註解排除不須要轉換成json的屬性數據,即Store對象關聯的Goods對象集合。

    //表示註解排除不須要轉換成json的屬性數據

    @JSON(serialize=false)

    public Set getGoodses() {

        return this.goodses;

    }

正確

 

第四步: 完善ajax代碼:編寫客戶端回調函數,處理返回數據

給select列表元素增長id屬性,用於選擇這個select:

<tr>

                            <td>

                                選擇倉庫:

                            </td>

                            <td>

                                <select class="tx" style="width:120px;" name="store.id" id="store_id">

                                    

                                </select>

                                (此信息從數據庫中加載)

                            </td>

                        </tr>

【回顧知識點】咱們前臺頁面拿到的是個數組,那麼如何在jQuery中遍歷數組:

第五步:加載倉庫的異步請求代碼:

<!-- 引入jquery庫 -->

<script type="text/javascript" src="${pageContext.request.contextPath }/js/jquery-1.8.3.js"></script>

<script type="text/javascript">

    //onload

    $(function(){

        //dom初始化後加載

        //$.post(請求url,請求參數,回調函數,返回的類型);

        $.post("${pageContext.request.contextPath}/store_listAjax.action",function(data){

            //data:轉換後的對象:json對象數組-dom對象

            $(data).each(function(){

                //this每個對象json

                //this.id

                var option=$("<option value='"+this.id+"'>"+this.name+"</option>");

                //添加到下拉列表中

                $("#store_id").append(option);

            });

        

        });

    });

 

</script>

 

 

  1. Spring和Ehcache緩存集成

業務問題:若是倉庫不常常變更,大量進出庫,老是須要查詢倉庫列表 (列表重複) ,使用緩存優化 !

 

spring緩存的配置原理:(註解)

 

 

第一步: 導入ehcache的jar 和 ehcache.xml

    ehcache-core-2.6.6.jar

spring-context-support.jar (spring支持jar,包含平臺緩存管理器)

第二步:在resources下建立ehcache.xml文件,配置自定義的緩存名稱<cache name="storemanager">

<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">

 

<diskStore path="java.io.tmpdir"/>

<defaultCache

maxElementsInMemory="10000"

eternal="false"

timeToIdleSeconds="120"

timeToLiveSeconds="120"

overflowToDisk="true"

maxElementsOnDisk="10000000"

diskPersistent="false"

diskExpiryThreadIntervalSeconds="120"

memoryStoreEvictionPolicy="LRU"

/>

<cache name="storemanager"

maxElementsInMemory="10000"

eternal="false"

timeToIdleSeconds="120"

timeToLiveSeconds="120"

overflowToDisk="true"

maxElementsOnDisk="10000000"

diskPersistent="false"

diskExpiryThreadIntervalSeconds="120"

memoryStoreEvictionPolicy="LRU"

/>

</ehcache>

 

 

第三步: 配置Spring的applicationContext.xml

引用cache 名稱空間

<beans xmlns="http://www.springframework.org/schema/beans"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xmlns:p="http://www.springframework.org/schema/p"

xmlns:context="http://www.springframework.org/schema/context"

xmlns:aop="http://www.springframework.org/schema/aop"

xmlns:tx="http://www.springframework.org/schema/tx"

xmlns:cache="http://www.springframework.org/schema/cache"

xsi:schemaLocation="http://www.springframework.org/schema/beans

http://www.springframework.org/schema/beans/spring-beans.xsd

http://www.springframework.org/schema/context

http://www.springframework.org/schema/context/spring-context.xsd

http://www.springframework.org/schema/aop

http://www.springframework.org/schema/aop/spring-aop.xsd

http://www.springframework.org/schema/tx

http://www.springframework.org/schema/tx/spring-tx.xsd

http://www.springframework.org/schema/cache

http://www.springframework.org/schema/cache/spring-cache.xsd">

    

 

第四步:註解方式完成配置:(重點)

兩步:

  1. 在覈心配置文件中開啓緩存驅動,而後在須要緩存或清除緩存的方法上加註解

    <!-- 配置緩存整合 -->

        <!-- ehcache管理器對象 -->

        <bean id="ehCacheManager" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">

            <!-- 默認讀取classpath:ehcache.xml -->

            <property name="configLocation" value="classpath:ehcache.xml"/>

        </bean>

        <!-- 具體的平臺緩存管理器 -->

        <bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager">

            <!-- 注入ehcache -->

            <property name="cacheManager" ref="ehCacheManager"/>

        </bean>

        <!-- 緩存註解驅動 -->

        <cache:annotation-driven cache-manager="cacheManager"/>

     

    (2)在StoreServiceImpl.java類中,使用註解開啓緩存

    代碼:

    查詢方法須要從緩存中查詢

    @Cacheable(value="storemanager")//放入緩存

        public List<Store> findAllStoreList() {

            return storeDao.findAll(Store.class);

        }

    增刪改方法能夠清理緩存

    @CacheEvict(value="storemanager",allEntries=true)//清除緩存區域的全部對象

        public void saveStore(Store store) {

            storeDao.save(store);

        }

     

    【擴展】,可將不一樣業務放置到不一樣的緩存,好比,將系統參數、分類,貨物、倉庫。。。。

     

    1. 重點和做業

     

    1. 架構搭建---登陸功能-- -代碼抽取—三層抽取---開發方法(先編碼—再配置)
    2. Crud的編程: 基本crud的步驟(值棧的使用,阻止默認事件),jquery引入
    3. 入庫: ajax加載(頁面加載後的加載—能夠改造更懶加載)
    4. 緩存的使用
相關文章
相關標籤/搜索