0

私はこのチュートリアルに従っています: http://www.scribd.com/doc/25244173/Java-Struts-Spring-Hibernate-Tutorial セットアップ (前述) はチュートリアル ファイルで正常に機能していましたが、変更-削除/更新アクションは発生しません。エラーや癖はありません。完全に無視されます。データの取得に関しては、すべてが完全に機能します..

tut のほとんどすべてのファイルは同じですが、これらの違いがあります。このチュートリアルでは、サービス ファイルを使用します。

Services.java

package services;

import org.springframework.transaction.annotation.Transactional;
import org.hibernate.SessionFactory;
import org.hibernate.Session;
import data.*;
import java.util.List;

// This class is the business services tier in the application.
// @Transactional is needed so that a Hibernate transaction is set up,
//  otherwise updates won't have an affect
@Transactional
public class Services {
    // So Spring can inject the session factory
    SessionFactory sessionFactory;
    public void setSessionFactory(SessionFactory value) {
        sessionFactory = value;
    }

    // Shortcut for sessionFactory.getCurrentSession()
    public Session sess() {
        return sessionFactory.getCurrentSession();
    }

    public Event getEventById(long id) {
        return (Event) sess().load(Event.class, id);
    }

    public Person getPersonById(long id) {
        return (Person) sess().load(Person.class, id);
    }

    public void deleteEventById(long id) {
        sess().delete(getEventById(id));
    }

    public void deletePersonById(long id) {
        sess().delete(getPersonById(id));
    }

    public void createEvent(String name) {
        Event theEvent = new Event();
        theEvent.setName(name);
        sess().save(theEvent);
    }

    public void createPerson(String name) {
        Person p = new Person();
        p.setName(name);
        sess().save(p);
    }

    @SuppressWarnings("unchecked")
    public List getEvents() {
        return sess().createQuery("from Event").list();
    }

    @SuppressWarnings("unchecked")
    public List getPeople() {
        return sess().createQuery("from Person").list();
    }

    public void removePersonFromEvent(int personId, int eventId) {
        getEventById(eventId).getPeople().remove(getPersonById(personId));
    }

    public void addPersonToEvent(int personId, int eventId) {
        getEventById(eventId).getPeople().add(getPersonById(personId));
    }
}

親コントローラーと HibernateUtil への静的呼び出しを使用して、ファイルを分離しようとしました: HibernateUtil.java

package com.epa.util;

import org.hibernate.SessionFactory;
import org.springframework.transaction.annotation.Transactional;
@Transactional
public class HibernateUtil {

    // So Spring can inject the session factory
    static SessionFactory sessionFactory;
    public void setSessionFactory(SessionFactory value) {
        sessionFactory = value;
    }

    // Shortcut for sessionFactory.getCurrentSession()
    public static SessionFactory getSessionFactory() {
        return sessionFactory;
    }
}

BaseController.java

package com.epa.controller.base;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.transaction.annotation.Transactional;

import com.epa.controller.EventController;
import com.epa.controller.PersonController;
import com.epa.util.HibernateUtil;

@Transactional
public class BaseController {

    protected SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
    // Shortcut for sessionFactory.getCurrentSession()
    public Session sess() {
        return sessionFactory.getCurrentSession();
    }

    private PersonController personController = null;
    private EventController eventController = null;

    public PersonController getPersonController() {
        if (this.personController == null) {
            this.personController = new PersonController();
        }
        return personController;
    }

    public EventController getEventController() {
        if (this.eventController == null) {
            this.eventController = new EventController();
        }
        return eventController;
    }
}

EventController.java

package com.epa.controller;

import java.util.List;

import org.springframework.transaction.annotation.Transactional;

import com.epa.controller.base.BaseController;
import com.epa.model.Event;

@Transactional
public class EventController extends BaseController {

    public Event getEventById(long id) {
        return (Event) sess().load(Event.class, id);
    }

    public void deleteEventById(long id) {
        sess().delete(getEventById(id));
    }

    public void createEvent(String name) {
        Event theEvent = new Event();
        theEvent.setName(name);
        sess().save(theEvent);
    }

    @SuppressWarnings("unchecked")
    public List getEvents() {
        return sess().createQuery("from Event").list();
    }

}

そして春の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:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="
       http://www.springframework.org/schema/beans 
       http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
       http://www.springframework.org/schema/tx 
       http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
       http://www.springframework.org/schema/aop 
       http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">

    <!-- The singleton hibernate session factory -->
    <bean id="sessionFactory" scope="singleton"
        class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
        <property name="configLocation" value="classpath:hibernate.cfg.xml" />
    </bean>

    <!-- Spring's hibernate transaction manager, in charge of making hibernate sessions/txns -->
    <bean id="transactionManager"
        class="org.springframework.orm.hibernate3.HibernateTransactionManager">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>

    <!-- So classes/functions with @Transactional get a hibernate txn -->
    <tx:annotation-driven />

    <!-- Inject my business services class to the actions 
    <bean id="services" class="com.epa.services.Services" scope="singleton">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean>-->

    <!-- Inject my business services class to the actions -->
    <bean id="hibernateUtil" class="com.epa.util.HibernateUtil" scope="singleton">
        <property name="sessionFactory" ref="sessionFactory" />
    </bean> 

    <bean id="baseController" class="com.epa.controller.base.BaseController" scope="singleton" />

</beans>
4

2 に答える 2

1

あなたのコードは、Spring の依存性注入の概念を完全には理解していないように見えます。これは、BaseControllerシングルトンを管理し、依存性を提供するという Spring の仕事を行っているためです。

問題

Spring に頼るのではなく、内部で自分でインスタンスを作成EventControllerしています。Spring は、クラス インスタンスの手動作成をインターセプトできず、Spring アノテーションでクラスにアノテーションを付けることによって、ここで必要なトランザクション動作をインスタンスに提供できません。PersonControllerBaseController@Transactional

解決

それでは、このコードをクリーンアップするためのパスを見つけてみましょう。最初にクラスを削除しHibernateUtilます。静的呼び出し、Java Bean の概念、および未使用のトランザクション動作が混在しているため、新しい抽象化レイヤーがもたらされるため、何のメリットもありません。からapplicationContext.xmlも削除することを忘れないでください。

を削除しBaseControllerて大幅な書き直しを行います。これは、このような環境で Spring 自体によって正しく管理されるSingleton applicationContext.xml-Factory として機能するためです。PersonControllerEventController

public abstract class BaseController {

    private SessionFactory sessionFactory;

    public void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }

    protected Session getCurrentSession() {
        return sessionFactory.getCurrentSession();
    }

}

この方法は、提供された HibernateオブジェクトBaseControllerを利用できる他の拡張クラスの抽象基本クラスになります。Sessionでは、あなたの に素敵なインターフェースを作成しましょうEventController

public interface EventController {

    Event getEventById(long id);

    void deleteEventById(long id);

    Event createEvent(String name);

    List getEvents();

}

EventControllerHibernate次に、Hibernate 用の上記のインターフェースの実装が必要なので、以前に作成した実装を利用して新しいクラスを呼び出しましょうBaseController

public class EventControllerHibernate extends BaseController implements EventController {

    @Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
    public Event getEventById(long id) {
        return (Event) getCurrentSession().get(Event.class, id);
    }

    @Transactional(propagation = Propagation.REQUIRED)
    public void deleteEventById(long id) {
        getCurrentSession().delete(getEventById(id));
    }

    @Transactional(propagation = Propagation.REQUIRED)
    public Event createEvent(String name) {
         return (Event) getCurrentSession().save(new Event(name));
    }

    @Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
    @SuppressWarnings("unchecked")
    public List getEvents() {
        return getCurrentSession().createQuery("from Event").list();
    }

}

applicationContext.xmlそして、必要なSessionFactoryものも提供されるように、Spring にこのクラスを正しく登録することを忘れないでください。

<bean id="eventController" class="com.epa.controller.EventControllerHibernate">
    <property name="sessionFactory" ref="sessionFactory" />
</bean> 

Spring からタイプ の Spring Bean を取得すると、内部に実装されたビジネス ロジックに委譲するインターフェイスをEventController完全に実装した、トランザクション対応のプロキシ オブジェクトが取得されます。EventControllerEventControllerHibernate

覚えておいてくださいnew EventControllerHibernate(): Spring はクラス インスタンスの手動作成をインターセプトできないため、これではうまくいかないため、アプリケーションでAが発生することはありません。プログラムでトランザクション対応インスタンスを取得すると、次のようになります。

ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
EventController eventController = context.getBean("eventController", EventController.class);
于 2011-03-12T17:39:18.647 に答える
0

コントローラコードはあまりエレガントではありません。codescapeがここで言ったことすべてに従う必要があります。ただし、問題の簡単な修正は次のようになります。新しいPersonController()または新しいEventController()を返す代わりに、BaseController()に注入された同じBeanインスタンスを返すことができます。これにより、@TransactionalがSpringによってインターセプトされる可能性のあるプロキシオブジェクトが返されます。しかし、私が言ったように、によって定義されたコントローラーは良いコードではありません。

于 2011-03-13T13:49:28.143 に答える