0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

POST送信の結果をモードレスウィンドウに表示する

0
Posted at

昔にモードレスウィンドウ&POST送信で躓いた記憶が残っていて、IntelliJにAIアシスタントがついていたので、昔にやったものがどんなものかを探りながら、初めて触るAIちゃんと一緒に頑張ってもらいながら書いてみました。
ボタン押下→window.open→POST送信→結果をモードレスウィンドウに表示するためモードレスウィンドウ用にPOST送信→モデルへ詰めてモードレスウィンドウのhtmlに返す みたいな内容。
window.openした後にPOST送信の結果をうんぬんするから、二回コントローラを叩いたような感じの実装でした。

フォルダの構成は以下。
src/
└── main/
├── java/
│ └── org/
│ └── example/
│ └── frontdemo/
│ ├── FrontdemoApplication.java
│ └── index/
│ ├── controller/
│ │ └── indexController.java
│ └── form/
│ └── Reqform.java
├── main.iml
└── resources/
├── application.properties
├── static/
│ └── js/
│ └── app.js
└── templates/
├── index.html
└── modelessWindow.html

indexController.java
package org.example.frontdemo.index.controller;

import org.example.frontdemo.index.form.Reqform;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;
import tools.jackson.core.type.TypeReference;
import tools.jackson.databind.ObjectMapper;

import java.util.Arrays;
import java.util.List;

@Controller
public class indexController {

    // ルートアクセス("/")で templates/index.html を返す
    @GetMapping("/")
    public String index() {
        return "index";
    }

    @PostMapping("/test1")
    @ResponseBody
    public ResponseEntity<List<Reqform>> test1(@RequestBody Reqform reqform) {
        return ResponseEntity.ok ( Arrays.asList ( reqform ) );
    }

    @PostMapping("/test2")
    public String test2(
            @RequestParam("testList") String json,
            Model model
    ) {
        ObjectMapper objectMapper = new ObjectMapper();
        try {
            // フロントは配列を送るため、明示的に List<Reqform> 型を指定してデシリアライズ
            List<Reqform> list = objectMapper.readValue(
                    json,
                    new TypeReference<List<Reqform>>() {}
            );
            list.add (new Reqform("山田太郎", "male"));
            model.addAttribute("testList", list);
            return "modelessWindow"; // modelessWindow.html
        } catch (Exception e) {
            // デバッグ用に簡易エラー表示(必要に応じて削除/ログ化)
            model.addAttribute("testList", java.util.Collections.emptyList());
            model.addAttribute("error", e.getMessage());
            return "modelessWindow";
        }
    }
}

Reqform.java
package org.example.frontdemo.index.form;

public class Reqform {
    private String name;
    private String sex;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public Reqform(String name, String sex) {
        this.name = name;
        this.sex = sex;
    }
}

index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="/js/app.js"></script>
</head>
<body>
    <input id="name" name="name">
    <input id="sex" name="sex">
    <button onclick="modelessWindow()">
        モードレスウィンドウ
    </button>
</body>
</html>
app.js
// 共通ユーティリティ
const toAbsoluteUrl = (u) => new URL(u, window.location.origin).href;

// モードレスウィンドウを開いてサーバ連携
function modelessWindow() {
  // ① ユーザー操作直後に window.open
  const target = '_testList';
  const modal = window.open('about:blank', target, 'width=1280,height=1080');

  // ② Ajax用リクエスト
  const requestBody = collectValuesById('name', 'sex');

  // ルート相対URLに統一(/test1)
  ajaxPost(
    '/test1',
    requestBody, function (response) {
      // ③ 別ウィンドウへ POST するパラメータ
      const param = {
        testList: JSON.stringify(response),
      };
      // POST 先もルート相対に統一(/test2)
      postToWindow('/test2', param, target);
    },
    function () {
      modal.close();
      alert('エラー');
    }
  );
}

// 指定した要素IDから value を収集してオブジェクト化
function collectValuesById(...elementIds) {
  const values = {};

  for (const id of elementIds) {
    const element = document.getElementById(id);
    values[id] = element?.value ?? '';
  }
  return values;
}

// JSON POST (fetch)
function ajaxPost(url, data, onSuccess, onError) {
  const abs = toAbsoluteUrl(url);
  fetch(abs, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(data),
  })
    .then((res) => {
      if (!res.ok) throw new Error('HTTP error');
      return res.json();
    })
    .then(onSuccess)
    .catch((err) => {
      if (onError) onError(err);
    });
}

// 別ウィンドウ(ターゲット)へフォームPOST
function postToWindow(url, params, targetName) {
  const form = document.createElement('form');
  form.method = 'post';
  form.action = toAbsoluteUrl(url);
  form.target = targetName;

  Object.keys(params).forEach(function (name) {
    const input = document.createElement('input');
    input.type = 'hidden';
    input.name = name;
    input.value = params[name];
    form.appendChild(input);
  });

  document.body.appendChild(form);
  form.submit();
  document.body.removeChild(form);
}
modelessWindow.html
<!DOCTYPE html>
<html lang="ja" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>モードレス画面</title>
    <style>
        table { border-collapse: collapse; }
        th, td { border: 1px solid #ccc; padding: 4px 8px; }
    </style>
    </head>
<body>
<h2>モードレス画面</h2>

<div th:if="${#lists.isEmpty(testList)}">
    データがありません。
    <div style="margin-top:8px; color:#666;" th:text="${testList}"></div>
    <!-- ↑ デバッグ用: 中身の確認。不要なら削除可 -->
    </div>

<table th:if="${!#lists.isEmpty(testList)}">
    <thead>
    <tr>
        <th>name</th>
        <th>sex</th>
    </tr>
    </thead>
    <tbody>
    <tr th:each="row : ${testList}">
        <td th:text="${row.name}">name</td>
        <td th:text="${row.sex}">sex</td>
    </tr>
    </tbody>
    </table>

</body>
</html>

初期画面
image.png

ボタン押下後(山田は複数出るか確認のため固定で入れちゃってる)
image.png

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?