2

2 つのコントローラーで @SessionAttributes を使用していますが、非常に奇妙な動作が発生しています。私の最初のコントローラー (ViewController) は、JSP ページを表示する単純なビュー コントローラーです。もう 1 つは、Ajax リクエストを処理するコントローラー (AjaxController) です。メンバーとして HashMap を持つ単なるオブジェクトであるセッション属性があります。オブジェクトはマップのラッパーです。マップはデータベースから読み込まれ、ViewController を介して正常に表示されるセッションに配置されます。ただし、ajax 要求 (AjaxController) を介してマップから削除を行い、ページを更新すると、ViewController は要素が削除されたことを示しますが、要素がまだそこにあることもあります。コード スニペットは次のとおりです。

ViewController (ホームページは、userSettings に含まれるマップのコンテンツを表示するだけです。

@Controller
@SessionAttributes({"userSettings"})
public class ViewController {

@RequestMapping(value="/", method=RequestMethod.GET)
    public String home(ModelMap model) {
        UserSettings userSettings = (UserSettings) model.get("userSettings");
        String userListenersJson = userSettings.toJson();  // for bootsrtapping the js on the front end

        return "views/home";
    }
}

Ajaxコントローラー:

@Controller
@SessionAttributes({"userSettings"})
public class AjaxController {

@RequestMapping(value="/users/listeners/{externalId}", method=RequestMethod.DELETE)
public @ResponseBody
AjaxResponse<?> deleteListener(ModelMap model,
        @PathVariable long externalId) {

            UserSettings userSettings = (UserSettings) model.get("userSettings");
            userSettings.removeSetting(externalId);
            return new AjaxResponse<String>(null, true);    
}
}

ここで @SessionAttributes を間違って使用していますか? なぜこれが時々うまくいくのですか?また、すべてのビューと ajax 機能を同じコントローラーに配置しようとしましたが、同じ動作を経験しました。

助けてくれてありがとう!

編集:

springsecurity を介して UserPrincipal を使用するために、コードを少しリファクタリングしました。私の理解では、このオブジェクトはセッションに保存されています。とにかく、まったく同じ動作が見られます。

ユーザー設定マップを設定する UserPrincipal コンストラクターを次に示します。ここでブレークポイントを設定して、正しい listenerDBO が設定されるようにしました。リスナーが db から CustomUserPrincipal の UserSettings オブジェクトに設定されるのはこれだけです。他のすべての追加/削除はコントローラーを介して行われます (簡単に言うと、追加は決して失敗しません... 削除のみです):

public CustomUserPrincipal(UserDBO userDBO) {
    // set UserSettings obj
    UserSettingsAdapter.addListeners(userDBO.getUserListenerDBOs(), userSettings);
}

UserSettings オブジェクト自体:

public class UserSettings implements Serializable {

    private static final long serialVersionUID = -1882864351438544088L;
    private static final Logger log = Logger.getLogger(UserSettings.class);

    private Map<Long, Listener> userListeners = Collections.synchronizedMap(new HashMap<Long, Listener>(1));

    // get the listeners as an arraylist
    public List<Listener> userListeners() {
        return new ArrayList<Listener>(userListeners.values());
    }

    public Map<Long, Listener> getUserListeners() {
        return userListeners;
    }

    public Listener addListener(Listener listener) {
        userListeners.put(listener.getId(), listener);
        return listener;
    }

    // I'm logging here to try and debug the issue. I do see the success
    // message each time this function is called
    public Listener removeListener(Long id) {
        Listener l = userListeners.remove(id);
        if (l == null) {
            log.info("failed to remove listener with id " + id);
        } else {
            log.info("successfully removed listener with id " + id);
        }

        log.info("Resulting map: " + userListeners.toString());
        log.info("Map hashcode: " + userListeners.hashCode());

        return l;
    }


    public Listener getListener(long id) {
        return userListeners.get(id);
    }
  }

これは、UserSettings オブジェクトに追加する UserSettingsAdapter クラスのヘルパー関数であり、CustomUserDetails コンストラクターから呼び出されます。

public static void addListeners(Set<UserListenerDBO> userListeners, UserSettings userSettings) {
    for (UserListenerDBO userListenerDBO : userListeners) {
        if (userListenerDBO.isActive()) {
            addListener(userListenerDBO, userSettings);
        }
    }
}

@SessionAttributes の代わりに CustomUserPrincipal オブジェクトを使用するようにコントローラー コードも変更しました。

ViewController で:

@RequestMapping(value="/", method=RequestMethod.GET)
public String home(ModelMap model) {
   CustomUserPrincipal userPrincipal = authenticationHelpers.getUserPrincipal();
   UserSettings userSettings = userPrincipal.getUserSettings();
   String userListenersJson = userSettings.toJson();
   return "views/home";
}

AjaxController では:

@RequestMapping(value="/users/listeners/{externalId}", method=RequestMethod.DELETE)
public @ResponseBody
AjaxResponse<?> deleteListener(ModelMap model,
        @PathVariable long externalId) {
   CustomUserPrincipal userPrincipal = authenticationHelpers.getUserPrincipal();
   UserSettings userSettings = userPrincipal.getUserSettings();
   userSettings.removeListener(externalId);

   return new AjaxResponse<String>(null, true); 
}

これが問題に光を当てるのに役立つことを願っています!

4

2 に答える 2

0

@SessionAttributesで同様の問題が発生しました。コントローラにはクラスレベルで@SessionAttributesアノテーションがあり、メソッドの1つがPOSTリクエストを処理し、セッション管理オブジェクトのインスタンスを引数として含めました。このインスタンスはデータベースに保存されましたが、後続のリクエストで再利用されたため、データが破損していました。SessionStatusタイプの別のメソッド引数を追加し、を呼び出す必要がありSessionStatus.setComplete()ました。これにより、インスタンスがセッションから削除され、再利用と破損が防止されました。したがって、SessionStatusインスタンスをコントローラーのハンドラーメソッドに追加し、必要に応じてsetComplete()を呼び出してみてください。

isComplete()編集:最初の回答で誤ってゲッターを参照しました。セッターを参照するつもりsetComplete()でした。

于 2012-06-05T19:16:03.937 に答える
0

@SessionAttributes はコントローラーに固有であり、複数のコントローラー間で共有されません。代わりに、session.setAttribute (クラス HttpSession) を手動で使用することを検討してください。

ここを見てください:http://beholdtheapocalypse.blogspot.fr/2013/01/spring-mvc-framework-sessionattributes.html

于 2013-09-19T07:18:40.513 に答える