パラメータを使用したRedirectAttributesの原則
1.概要:一部の関数は、リダイレクト時に最後のリクエストのパラメーターを取得する必要があります。最初のメソッドはリダイレクトしてパラメーターをスプライスでき、2番目のメソッドはニーズを追加するためにRedirectAttributesにすることができます。パラメーターをリダイレクトする方法は2つありますベルト、およびRedirectAttributes。次に、リダイレクトされたリクエストがページに戻ったときに、リクエストのパラメータを取得するか、@ ModelAttributeを使用して取得できます。
RedirectAttributesは、パラメーターを使用して2つの方法でリダイレクトします。
方法1:attr.addAttribute(key、value)を使用します。これは、要求パラメーターをスプライシングし、リダイレクトする必要のある要求にそれらを追加する方法です。
方法2:attr.addFlashAttribute(key、value)を使用します。これは、セッションを通じてパラメーターデータを一時的に保存し、次のリダイレクト中に一時的に保存されたパラメーターデータを取得します。
/**
* 1、原始请求: /demo2/redirect
*/
@RequestMapping("/redirect")
public String RedirecAttr(RedirectAttributes attr){
attr.addAttribute("id", 1); // 方式1: 即拼接id=1
attr.addFlashAttribute("result", "成功"); // 方式2
return "redirect:/demo2/list";
}
/**
* 2、重定向的请求: 在浏览器显示的链接是 /demo2/list?id=1
*/
@RequestMapping("list")
public String list(int id,String result, @ModelAttribute("result") String result2){
System.out.println(id); // 可以获取参数
System.out.println(result); // 无法获取参数
System.out.println(result2); // 可以获取参数
return "/index"; // 页面${result}可以获取参数的值
}
2、ソースコード分析
1.問題を分析しますか?
リクエストパラメータはいつセッションに保存されますか?リクエストパラメータはいつセッションから削除されますか?セッションには何が保存されますか?
2.リクエストパラメータはいつセッションに保存されますか?
attr.addFlashAttribute(key、value)を処理メソッドに追加します。処理メソッドが終了した後、リダイレクトする前に、RedirectAttributesのすべてのパラメーターがFlashMapに追加され、OUTPUT_FLASH_MAPをキーとして要求フィールドに入力されます。リクエストプロセスを追跡し、RequestMappingHandlerAdapterでgetModelAndViewメソッドを見つけることができます。
private ModelAndView getModelAndView(ModelAndViewContainer mavContainer,
ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception {
......省略
if (model instanceof RedirectAttributes) {
Map<String, ?> flashAttributes = ((RedirectAttributes) model).getFlashAttributes();
HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes);
}
return mav;
}
@SuppressWarnings("unchecked")
public static Map<String, ?> getInputFlashMap(HttpServletRequest request) {
return (Map<String, ?>) request.getAttribute(DispatcherServlet.INPUT_FLASH_MAP_ATTRIBUTE);
}
public static FlashMap getOutputFlashMap(HttpServletRequest request) {
return (FlashMap) request.getAttribute(DispatcherServlet.OUTPUT_FLASH_MAP_ATTRIBUTE);
}
でRequestContextUtils、我々は要求フィールドで2 flashMapsがあることがわかります。私たちは、最初のflashMap構造を探索しません。InputFlashMapは、前回の要求からリダイレクトされたパラメータであり、そしてoutFlashMapはニーズが、この時間をリダイレクトするというパラメータであり、 、ここではリクエストドメインに配置するだけで、いつ、何をセッションに配置するかを確認するために見下ろす必要があります。リダイレクトビューRedirectViewの処理を追跡する必要があります。
でRedirectView、我々は見つけることができますoutFlashMapセッションで通過FlashMapManager renderMergedOutputModel()メソッド。今のところ、FlashMapManagerの内部の詳細を見ないでください。'
protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request,
HttpServletResponse response) throws IOException {
// 从请求域取出FlashMap
FlashMap flashMap = RequestContextUtils.getOutputFlashMap(request);
if (!CollectionUtils.isEmpty(flashMap)) {
FlashMapManager flashMapManager = RequestContextUtils.getFlashMapManager(request);
// 放入session中
flashMapManager.saveOutputFlashMap(flashMap, request, response);
}
// 重定向
sendRedirect(request, response, targetUrl, this.http10Compatible);
}
3.リクエストパラメータはいつセッションから削除されますか?
検索セッションパラメータ要求でもある検索セッションからを通してFlashMapManager処理方法が処理される前に、そして我々ができ見つけるそれをするdoDispatch方法のDispatcherServlet。
FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
if (inputFlashMap != null) {
request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
}
request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
retrieveAndUpdate、つまり、セッションinputFlashMapから削除されたFlashMapManagerによって、リクエストフィールドに、フォローアップ時にパラメータ分析ModelAttributeに入れられ、そこでoutFlashMapが初期化されます。
4.セッションを保存する具体的な方法は何ですか?
今、私たちは取り出して中に入れのタイミングと方法を理解していることを、彼らはすべて取ると場所FlashMapはオブジェクトを通じてFlashMapManager、それでは見てみましょうFlashMapクラスとFlashMapManagerクラスを。
FlashMapはHashMapを継承します。拡張機能の主な機能は、有効期限を追加することです。これを作成するときに、有効期限を設定し、取得時に有効期限が切れるかどうかを判断します。
public void startExpirationPeriod(int timeToLive) {
this.expirationStartTime = System.currentTimeMillis();
this.timeToLive = timeToLive;
}
public boolean isExpired() {
return (this.expirationStartTime != 0 &&
(System.currentTimeMillis() - this.expirationStartTime > this.timeToLive * 1000));
}
FlashMapManagerの継承構造
パラメータの取得:AbstractFlashMapManagerのretrieveAndUpdateメソッドは、主にテンプレートメソッドretrieveFlashMapsを介してサブクラスSessionFlashMapManagerを呼び出してFlashMapリストを取得し、期限切れのリストを削除することで実装されます。一致するパスは要求されたパスと一致します。居住者は、retrieveAndUpdateメソッドがsessipnに格納されている最後のリクエストパラメーターを取得する方法を確認する必要があります。
public final FlashMap retrieveAndUpdate(HttpServletRequest request, HttpServletResponse response) {
List<FlashMap> allFlashMaps = retrieveFlashMaps(request); // 模板方法,子类sessin中取
if (CollectionUtils.isEmpty(allFlashMaps)) {
return null;
}
List<FlashMap> mapsToRemove = getExpiredFlashMaps(allFlashMaps); // 过期的
FlashMap match = getMatchingFlashMap(allFlashMaps, request); // 匹配当前请求的
if (match != null) {
mapsToRemove.add(match);
}
if (!mapsToRemove.isEmpty()) {
if (logger.isDebugEnabled()) {
logger.debug("Removing FlashMap(s): " + mapsToRemove);
}
Object mutex = getFlashMapsMutex(request);
if (mutex != null) { // 如果加锁就已sesison为锁进行更新FlashMaps的操作
synchronized (mutex) {
allFlashMaps = retrieveFlashMaps(request);
if (allFlashMaps != null) {
allFlashMaps.removeAll(mapsToRemove); // 移除失效
updateFlashMaps(allFlashMaps, request, response); // 更新剩余的
}
}
}
else {
allFlashMaps.removeAll(mapsToRemove);
updateFlashMaps(allFlashMaps, request, response);
}
}
return match;
}
SessionFlashMapManagerのretrieveFlashMapsメソッドは、セッションからFlashMapをフェッチすることです。
protected List<FlashMap> retrieveFlashMaps(HttpServletRequest request) {
HttpSession session = request.getSession(false);
return (session != null ? (List<FlashMap>) session.getAttribute(FLASH_MAPS_SESSION_ATTRIBUTE) : null);
}
パラメータの保存:パラメータの保存は、SessionFlashMapManagerのsaveOutputFlashMapメソッドであり、flashMapのパスと有効期限を設定し、それらをセッションに保存します。
public final void saveOutputFlashMap(FlashMap flashMap, HttpServletRequest request, HttpServletResponse response) {
String path = decodeAndNormalizePath(flashMap.getTargetRequestPath(), request);
flashMap.setTargetRequestPath(path); // 设置目标路径
decodeParameters(flashMap.getTargetRequestParams(), request);
flashMap.startExpirationPeriod(getFlashMapTimeout()); // 设置过期时间180秒
Object mutex = getFlashMapsMutex(request);
if (mutex != null) { // 如果有锁就以session为锁操作session
synchronized (mutex) {
List<FlashMap> allFlashMaps = retrieveFlashMaps(request);
allFlashMaps = (allFlashMaps != null ? allFlashMaps : new CopyOnWriteArrayList<FlashMap>());
allFlashMaps.add(flashMap); // 添加
updateFlashMaps(allFlashMaps, request, response); // 更新
}
}
else {
List<FlashMap> allFlashMaps = retrieveFlashMaps(request);
allFlashMaps = (allFlashMaps != null ? allFlashMaps : new LinkedList<FlashMap>());
allFlashMaps.add(flashMap);
updateFlashMaps(allFlashMaps, request, response);
}
}
三、終わり
spring-mvcのredirectAttributesは、セッションを使用してリダイレクトパラメータを一時的に保存します。リダイレクトする場合、redirectAttributesのパラメータはFlashMapにコピーされ、FlashMapManagerを介してセッションに保存されます。次のリクエストが行われると、それが取得されます。このリクエストは、セッションに保存されているFlashMapと一致し、パラメータが解析されるときに@ModelAttributeに追加されます。