Help us understand the problem. What is going on with this article?

Springboot + HandsOnTableで一覧編集ができるフォームを作成する。

SpringBoot+HandsOnTableで、テーブルの一覧をExcel風に編集できる画面を作成する

従業員マスタを編集するイメージです。

1.従業員マスタ

Employee.java
import java.io.Serializable;
import com.fasterxml.jackson.annotation.JsonFormat;
import lombok.Data;
@Data
public class Employee implements Serializable {
    //選択の有無
    private boolean selected;
    //従業員番号
    private long empNo;
    //従業員氏名
    private String empName;
    //役職
    private String position;
    //採用日
    @JsonFormat(pattern = "yyyy/MM/dd")
    private String hireDate;
    public Employee() { }
    public Employee(long empNo, String empName, String position, String hireDate) {
        this.empNo=empNo;
        this.empName=empName;
        this.position=position;
        this.hireDate=hireDate;
    }
}
EmployeeListForm.java
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import lombok.Data;
@Data
public class EmployeeListForm implements Serializable {
    List<Employee> list=new ArrayList<Employee>();
}

2.Controller

(1) 初期表示用

HeloController.java
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

@Controller
public class HeloController {
    @RequestMapping("/")
    public String top() {
        return "index";
    }
    @RequestMapping(value="/regist", method=RequestMethod.POST)
    public String regist(
        @ModelAttribute EmployeeListForm form,
        Model model) {
        model.addAttribute("form", form);
        for (Employee emp: form.getList()) {
            System.out.println(emp.toString());
        }
        return "index";
    }
}

(2) HandsOnTableのData

HandsOnTableにマッピングする従業員マスタの一覧を取得するメソッド。

HeloRestController.java
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HeloRestController {
    @RequestMapping("/getEmpoyeeList")
    public List<Employee> getEmpoyeeList() {
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy/MM/dd");
        List<Employee> list = new ArrayList<>();
        for (int i=0; i< 1000; i++) {
            list.add(
                new Employee((i+1),
                "name-"+String.valueOf((i+1)),
                String.valueOf(i%4 + 1),
                LocalDate.now().format(dateTimeFormatter)));
        }
        return list;
    }
}

3.html

index.html
<!DOCTYPE html>
<html lang="ja" xmlns="http://www.w3.org/1999/xhtml"
    xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<link th:href="@{/handsontable/handsontable.full.min.css}" rel="stylesheet" />
<script th:src="@{/webjars/jquery/3.3.1/jquery.min.js}"></script>
</head>
<body>
    <input type="hidden" id="posturl" th:value="@{/getEmpoyeeList}"/>
    <form id="postform" th:action="@{/regist}" method="post">
    </form>
    <H3>Hands on Table サンプル</H3>
    <p>行を追加するには、右クリックして「上に行を挿入」を選択します<p>
    <div style="height:600px;width:1000px;padding:10px;">
        <div id="grid" class="handsontable"></div>
    </div>
    <button type="button" id="send">送信</button>
    <br>
    <script th:src="@{handsontable/handsontable.full.min.js}"></script>
    <script th:inline="javascript">
    /*<![CDATA[*/

    /** HandsOnTableのコンテナ  */
    var container = document.getElementById('grid');  //後ほど表を展開する要素を指定
    /** HandsOnTableオブジェクト  */
    var htable;
    /** HandsOnTableのヘッダ  */
    var header;
    /** HandsOnTableのData  */
    var jsondata;

    /** ajaxを実行する  */
    function executeAjax(ajaxUrl, ajaxType, formData){
      return $.ajax({
        url: ajaxUrl,
        type: ajaxType,
        contentType:false,
        processData: false,
        cache: false,
        data: formData,
        timeout: 30000
      });
    }

    //HandsOnTableオブジェクト作成
    function createHandsOnTable(jsonData){

        jsondata = jsonData;
        //ヘッダを編集
        header = new Array();
        var count = 0;
        for(key in jsondata[0]){
          header[count] = key;
          count++;
        }
        htable = new Handsontable(container, {
          //以下はデータ指定と表示オプション
          data: jsondata,        //JsonData
//        minSpareRows: 1,       //表の一番下にいくつ空行を表示するか。今回は1行を空行にして表示する。
          colHeaders: header,    //カラムの名前を表示するかどうか colheader: true 表示/false 非表示
                                 //カラムの名前を任意の名前にする colheader: 配列(カラム名)
          columns: [
            //選択
            {data:"selected",type: 'checkbox'},
            //従業員番号
            {data:"empNo",type: 'numeric'},
            //従業員氏名
            {data:"empName",type: 'text'},
            //採用日は、autocomplete
            {
                data:"position",
                type: 'autocomplete',
                source: ['1', '2', '3', '4'],
                strict: true,
                allowInvalid: false,
                filter: false
            },
            //入社日
            {data:"hireDate",type: 'date',dateFormat: 'YYYY/MM/DD'}
          ],
          rowHeaders: true,      //行番号の表示
          height: 600,           //テーブルの高さ
          contextMenu: {
              items: { row_above: {name: '上に行を挿入'}
              }
          },     //セルを右クリックしたときの行挿入を表示する。
          columnSorting: true,    //カラムのヘッダーをクリックした際に昇順、再クリックで降順にソート
          enterBeginsEditing: false, //true=Enterで次の行に移動する
          search: true
        });
    }

    function postSelectedRows(form){
        //HandsOnTableで選択された行をサーバにPOST送信する。
        var cols = htable.countCols();
        var rows = htable.countRows();
        list_idx=0;
        for (i=0; i< rows; i++) {
            //選択しているデータのみを送信する。
            if (htable.getDataAtCell(i,0)==true){
                for (j=0; j< cols; j++) {
                    var paramname="list["+list_idx+"]." + htable.getColHeader(j);
                    var paramvalue= htable.getDataAtCell(i,j);
                    $("<input>",{
                            type:"hidden",
                            name:paramname,
                            value:paramvalue
                    })
                    .appendTo($(form));
                }
                list_idx++;
            }
        }
        $(form).submit();
    }
    $(document).ready(function () {
        //handsOnTableのデータをサーバからAjaxをcallして取得します。
        var urladdress=$('#posturl').val();
        var fd = new FormData();
        executeAjax(urladdress, "post",fd)
        .done(function(data, textStatus, jqXHR) {
            createHandsOnTable(data);
        })
        .fail(function(jqXHR, textStatus, errorThrown){
          console.log('通信失敗');
        });
        $("#send").click(function() {
            postSelectedRows($('#postform'));
            return false;
        })
    });
    /*]]>*/
    </script>
</body>
</html>

createHandsOnTable・・HeloRestController#getEmpoyeeListからJSONオブジェクトをAjaxで取得してHandsOnTableにデータをセットします。
postSelectedRows・・・画面上で「checkbox」をチェックした行をフォームに追加してサーバに送信します。この処理で、input要素を生成していますが、name属性は、list[].変数名とすることで、post送信(HeloController#regist)したときに、ModelAttirbuteのフォーム属性にマッピングできるようにしています。

マッピングできれば、あとはデータベースに登録するなり処理できます。

HandsOnTableは、Excel風の編集ができるので通常の入力フォームより受けがよいと考えます。

参考にしたサイト
Handsontable 使い方メモ3(カラム・セルオプション)

以上

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした