1

注: 最終的な目標は、コードに示すように、結果の URL を "/public/academy/register?param=blah" からカスタマイズされた SEO 化された URL に変更することです。POST マッピングで「成功ビュー」JSP を返すのではなく、代わりに post-redirect-get を使用するように変更しようとして間違った道を進んでいる場合 (これはとにかく良い習慣です)、私は提案を受け入れます。

以下に、登録フォームを取得して処理する POST リクエスト マッピングと、成功ページのマッピング メソッドの 2 つのメソッドを示します。最初のメソッドに POST されたフォームを保持するリダイレクトにフラッシュ属性を追加しています。

フォームには のプロパティ階層がありForm -> Schedule -> Course -> Content -> Vendors、ベンダーが であることを除いて、それぞれが独自のクラス オブジェクトSortedSet<Vendor>です。成功ページをロードすると、ベンダーを遅延初期化できなかったことを示す Hibernate 例外が発生します。ロードが停止するほどチェーンの下流にあるのはなぜですか、またはもっと基本的には、そもそもなぜこのプロパティ値が失われるのでしょうか? 戻る前にブレークポイントを設定すると、RedirectAttributes オブジェクトには、渡した形式で Vendors が入力されます。何を与える?

@RequestMapping(value = "/public/academy/register", method = RequestMethod.POST)
public String processSubmit(Site site, Section section, User user,
        @ModelAttribute @Valid AcademyRegistrationForm form,
        BindingResult result, Model model, RedirectAttributes redirectAttributes) {
    validator.validate(form, result);

    if (site.isUseStates()
            && StringUtils.isBlank(form.getBooker().getState())) {
        result.rejectValue("booker.state",
                "gui.page.academy.attendee.state");
    }

    if (result.hasErrors()) {
        LOG.debug("Form has errors: {}", result.getAllErrors());
        return "common/academy-registration";
    }

    // Form is valid when no errors are present. Complete the registration.
    AcademyRegistration registration = form.toAcademyRegistration();
    academyService.performRegistration(registration, site);

    redirectAttributes.addFlashAttribute(form);

    String redirectUrl = "redirect:/public/academy/register/"
        + registration.getSchedule().getCourse().getContent().getSeoNavTitle() 
        + "-completed";

    return redirectUrl;
}

@RequestMapping(value="/public/academy/register/**-completed", method=RequestMethod.GET)
public String displayRegistrationSuccess(@ModelAttribute("academyRegistrationForm") final AcademyRegistrationForm form)
{
    SortedSet<Vendor> dummy = form.getSchedule().getCourse().getContent().getVendors();
    return "common/academy-registration-success";
}

例外は次のとおりです。

Oct 2, 2013 2:11:31 PM org.apache.catalina.core.ApplicationDispatcher invoke
SEVERE: Servlet.service() for servlet jsp threw exception
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.horn.cms.domain.Content.vendors, could not initialize proxy - no Session
4

1 に答える 1

1

これが私が想定していることです(詳細を更新するまで):

AcademyRegistration registration = form.toAcademyRegistration();
academyService.performRegistration(registration, site);

いくつかの Hibernate クエリを実行し、永続化されたエンティティを遅延して取得します。それらは初期化されていません。発生したロードは、おそらくいくつかの Hibernate で発生しましたSession(@Transactionalどこかにありますか?)。はSession閉じられ、遅延ロードされたオブジェクトから関連付けが解除されます。

次にform、遅延ロードされたエンティティ (休止状態のプロキシになります) へのネストされた参照を持つオブジェクトをRedirectAttributes. あなたがしているのは参照を渡すことだけなので、これ自体は問題ではありません。

リクエストの処理は、302 レスポンスを送信することで完了します。クライアントは、displayRegistrationSuccess()この行によって処理され、ヒットする新しいリクエストを作成します

SortedSet<Vendor> dummy = form.getSchedule().getCourse().getContent().getVendors();

ここで、formオブジェクトは前のリクエストで追加されたものと同じです。この参照チェーン内のオブジェクトの 1 つは、遅延初期化された Hibernate プロキシです。オブジェクトはもはや に関連付けられていないためSession、Hibernate は不平を言い、例外が発生します。

永続的な状態に依存するオブジェクトを (リクエストの境界を越えて) 渡すことはお勧めできません。代わりに、エンティティの取得に使用する ID を渡す必要があります。別の方法は、メソッド内でオブジェクトを完全に初期化することacademyServiceです。

于 2013-10-02T17:58:29.583 に答える