### 実現したいこと：

Quillのエディタを使ってデータを取得して、その情報をデータベースに追加し表示したい。

具体的には、formタグを使ってQuillというライブラリのエディタから入力したデータ(JSON?)をデータベースにVARCHAR型で追加し、そのデータをJavaを使って取得し、jspファイルに表示したいです。  
データベースはMySQLを使っています。  
JavaScriptの知識が全くなく、どのようにすればデータベースに追加すればいいかわかりません。  
参考にしたサイトも仕組みが理解できていないので、データがどこに保存されているのかも分かりません。

### 参考にしたサイト：

<http://sashimistudio.site/quilljs/>  
<https://quilljs.com/playground/#form-submit>  
<https://quilljs.com/>

### 現在の状況：

JSPとServletの基本的な使い方が理解できている程度です。

現在の状況の追加説明します。

現在タスク管理アプリケーションの課題内容の部分にリッチテキストを実装したいと考えています。  
表示する際には、ログインしたときのidとtaskidを使って課題を取得してfor文で内容を繰り返し表示するようにしています。  
現在の状況だと、jsonデータがそのまま出力されてしまうので、その部分を復元して表示したいと考えています。

**追記2回目：**  
理解が足らなく申し訳ありません。  
追記していただいたjsの内容を追加して、Block2の内容をjspファイルに書き込み、valueの部分にデータベースから取得したString型のjsonデータの内容を入れたのですが、出力されませんでした。

Block1とBlock2は課題登録と書かれているのですが、これはデータを表示するものではないのでしょうか？

自分の考えとしては、データベースにあるString型のjsonデータをBlock2のValueに入れることで、jsonデータの形が通常の文字（リッチテキスト）として表示されると考えているのですが合っていますでしょうか？

追記：himenonさんに教えていただいたやり方でエディタ上に出力できました。ありがとうございます。

```

    // このファイルは"quillcustom.js"です
    
    const quill = new Quill("#editor-container", {
      theme: "snow"
    });
    
    // サーバーから返ってきた値をセットする
    try {
      if (window.SERVER_TEXT && typeof window.SERVER_TEXT === "string") {
        const restoreContents = JSON.parse(window.SERVER_TEXT); // string -> jsonへ変換
        quill.setContents(restoreContents);
      }
    } catch (error) {
      console.error(error);
    }
    
    const form = document.querySelector("form");
    const contentsInput = document.querySelector("input[name=contents]");
    
    form.onsubmit = () => {
      contentsInput.value = JSON.stringify(quill.getContents());
      return true;
    };
    
    // このファイルは"quillcustom.js"です
    
    /**
     * Quillエディターの諸々の設定を行う
     *
     * @param HTMLElement
     *            target Quillエディタを描画するElement
     * @param string |
     *            undefined defaultContents 初期値
     */
    const createQuillEditor = (target, defaultContents) => {
      const quill = new Quill(target, {
        theme: "snow",
      });
      try {
        if (defaultContents) {
          const restoreContents = JSON.parse(defaultContents); // string -> jsonへ変換
          quill.setContents(restoreContents);
        }
      } catch (error) {
        console.error(error);
      }
      return quill;
    };
    
    /**
     * containerを基準にElementに対してEventHandlerを登録する
     *
     * @param HTMLDivElement
     *            container
     */
    const setupFormContainer = (container) => {
      const form = container.querySelector("form");
      const editor = container.querySelector(".editor");
      const contentsInput = container.querySelector("input[name=contents]");
      const quill = createQuillEditor(editor, contentsInput.value);
      form.onsubmit = () => {
        contentsInput.value = JSON.stringify(quill.getContents());
        return true;
      };
    };
    
    const initialize = () => {
      const containers = document.querySelectorAll(".form-container");
      Array.from(containers).forEach((container) => {
        setupFormContainer(container);
      });
    };
    
    initialize();Fs
```

```

    @import
        url(https://fonts.googleapis.com/css?family=Source+Sans+Pro:200,300,400,700)
        ;
    
    @import
        url(https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css)
        ;
    
    @import
        url(https://maxcdn.bootstrapcdn.com/font-awesome/4.1.0/css/font-awesome.min.css)
        ;
    
    * {
        margin: 0;
        padding: 0;
    }
    
    html {
        background-color: #333333
    }
    
    body {
        background-color: #333333
    }
    
    body, input, button {
        font-family: 'Source Sans Pro', sans-serif;
    }
    
    .login {
        padding: 15px;
        width: 400px;
        min-height: 400px;
        margin: 2% auto 0 auto;
    }
    
    .login .heading {
        text-align: center;
        margin-top: 1%;
    }
    
    .login .heading h2 {
        font-size: 3em;
        font-weight: 300;
        color: rgba(255, 255, 255, 0.7);
        display: inline-block;
        padding-bottom: 5px;
        text-shadow: 1px 1px 3px #23203b;
    }
    
    .login form .input-group {
        border-bottom: 1px solid rgba(255, 255, 255, 0.1);
        border-top: 1px solid rgba(255, 255, 255, 0.1);
    }
    
    .login form .input-group:last-of-type {
        border-top: none;
    }
    
    .login form .input-group span {
        background: transparent;
        min-width: 53px;
        border: none;
    }
    
    .login form .input-group span i {
        font-size: 1.5em;
        color: rgba(255, 255, 255, 0.2);
    }
    
    .login form input.form-control {
        display: block;
        width: auto;
        height: auto;
        border: none;
        outline: none;
        box-shadow: none;
        background: none;
        border-radius: 0px;
        padding: 10px;
        font-size: 1.6em;
        width: 100%;
        background: transparent;
        color: #c2b8b1;
    }
    
    .login form input.form-control:focus {
        border: none;
    }
    
    .login form button {
        margin-top: 20px;
        background: #27AE60;
        border: none;
        font-size: 1.6em;
        font-weight: 300;
        padding: 5px 0;
        width: 100%;
        border-radius: 3px;
        color: #b3eecc;
        border-bottom: 4px solid #1e8449;
    }
    
    .login form button:hover {
        background: #30b166;
        -webkit-animation: hop 1s;
        animation: hop 1s;
    }
    
    .float {
        display: inline-block;
        -webkit-transition-duration: 0.3s;
        transition-duration: 0.3s;
        -webkit-transition-property: transform;
        transition-property: transform;
        -webkit-transform: translateZ(0);
        transform: translateZ(0);
        box-shadow: 0 0 1px rgba(0, 0, 0, 0);
    }
    
    .float:hover, .float:focus, .float:active {
        -webkit-transform: translateY(-3px);
        transform: translateY(-3px);
    }
    
    /* Large Devices, Wide Screens */
    @media only screen and (max-width: 1200px) {
        .login {
            width: 600px;
            font-size: 2em;
        }
    }
    
    @media only screen and (max-width: 1100px) {
        .login {
            margin-top: 2%;
            width: 600px;
            font-size: 1.7em;
        }
    }
    /* Medium Devices, Desktops */
    @media only screen and (max-width: 992px) {
        .login {
            margin-top: 1%;
            width: 550px;
            font-size: 1.7em;
            min-height: 0;
        }
    }
    /* Small Devices, Tablets */
    @media only screen and (max-width: 768px) {
        .login {
            margin-top: 0;
            width: 500px;
            font-size: 1.3em;
            min-height: 0;
        }
    }
    /* Extra Small Devices, Phones */
    @media only screen and (max-width: 480px) {
        .login {
            margin-top: 0;
            width: 400px;
            font-size: 1em;
            min-height: 0;
        }
        .login h2 {
            margin-top: 0;
        }
    }
    /* Custom, iPhone Retina */
    @media only screen and (max-width: 320px) {
        .login {
            margin-top: 0;
            width: 200px;
            font-size: 0.7em;
            min-height: 0;
        }
    }
    
    /* ログイン成功画面 */
    .loginSuccess {
        padding: 15px;
        width: 400px;
        min-height: 400px;
        margin: 2% auto 0 auto;
    }
    
    .loginSuccess .heading h2 {
        font-size: 3em;
        font-weight: 300;
        color: rgba(255, 255, 255, 0.7);
        display: inline-block;
        padding-bottom: 5px;
        text-shadow: 1px 1px 3px #23203b;
    }
    /* メニュー画面 */
    .menu {
        padding: 15px;
        width: 400px;
        min-height: 400px;
        margin: 2% auto 0 auto;
    }
    
    .menu .heading h2 {
        font-size: 3em;
        font-weight: 300;
        color: rgba(255, 255, 255, 0.7);
        display: inline-block;
        padding-bottom: 5px;
        text-shadow: 1px 1px 3px #23203b;
    }
    
    /* トップ画面 */
    .welcome {
        padding: 15px;
        width: 500px;
        min-height: 400px;
        margin: 2% auto 0 auto;
    }
    
    .welcome .heading h2 {
        font-size: 2em;
        font-weight: 300;
        color: rgba(255, 255, 255, 0.7);
        display: inline-block;
        padding-bottom: 5px;
        text-shadow: 1px 1px 3px #23203b;
        text-align:center
    }
    
    
    /* 完了画面 */
    .success {
        padding: 15px;
        width: 400px;
        min-height: 400px;
        margin: 2% auto 0 auto;
    }
    
    .success .heading h2 {
        font-size: 3em;
        font-weight: 300;
        color: rgba(255, 255, 255, 0.7);
        display: inline-block;
        padding-bottom: 5px;
        text-shadow: 1px 1px 3px #23203b;
    }
    
    /* 課題登録・更新画面 */
    .taskD h2 {
        font-size: 3em;
        font-weight: 300;
        color: rgba(255, 255, 255, 0.7);
        display: inline-block;
        padding-bottom: 5px;
        text-shadow: 1px 1px 3px #23203b;
    
    }
    
    /* ボタン */
    .btn-square-slant {
        display: inline-block;
        position: relative;
        padding: 0.5em 1.4em;
        text-decoration: none;
        background: #30b166; /*ボタン色*/
        color: #FFF;
        border-bottom: solid 5px #36528c; /*ボタン色より暗めに*/
        border-right: solid 5px #5375bd; /*ボタン色より暗めに*/
    }
    
    .btn-square-slant:before {
        content: " ";
        position: absolute;
        bottom: -5px;
        left: -1px;
        width: 0;
        height: 0;
        border-width: 0 6px 6px 0px;
        border-style: solid;
        border-color: transparent;
        border-bottom-color: #FFF;
    }
    
    .btn-square-slant:after {
        content: " ";
        position: absolute;
        top: -1px;
        right: -5px;
        width: 0;
        height: 0;
        border-width: 0px 6px 6px 0px;
        border-style: solid;
        border-color: #FFF;
        border-bottom-color: transparent;
    }
    
    .btn-square-slant:active {
        /*ボタンを押したとき*/
        border: none;
        -webkit-transform: translate(6px, 6px);
        transform: translate(6px, 6px);
    }
    
    .btn-square-slant:active:after, .btn-square-slant:active:before {
        content: none; /*ボタンを押すと線が消える*/
    }
    
    .buttons {
        display: table;
        width: 100%;
        margin: 2% auto 0 auto;
        /* 子要素の幅の均等化 */
        table-layout: fixed;
    }
    
    .buttons a {
        margin-left: 60px;
    }
    
    /* テーブル */
    .tableD {
        width: 100%;
        border-collapse: collapse;
    }
    
    .tableD tr {
        background-color: #333333;
    }
    
    .tableD tr:last-child * {
    
    }
    
    .tableD th, table td {
        text-align: center;
        border: solid 2px #fff;
        color: white;
        padding: 10px 0;
    }
    
    /* 文字入力色 */
    input {
        color: #333333;
    }
    
    textarea {
        color: #333333;
    }
    
    .label {
        color: white; /* 文字色を白にする */
    }
```

```

    <%@ page language="java" contentType="text/html; charset=UTF-8"
        pageEncoding="UTF-8"%>
    
    <%@ page import="entity.TaskDataDTO"%>
    <%@ page import="java.util.List"%>
    <%@ page import="java.util.ArrayList"%>
    <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="UTF-8">
    <link rel="stylesheet" type="text/css" href="/TaskApp/css/common.css">
    <title>課題一覧表示画面</title>
    <script src="https://cdn.quilljs.com/1.3.6/quill.js"></script>
    <link href="https://cdn.quilljs.com/1.3.6/quill.snow.css"
        rel="stylesheet">
    <link href="https://cdn.quilljs.com/1.3.6/quill.bubble.css"
        rel="stylesheet">
    </head>
    <body>
        <table class="tableD">
            <tr>
                <td>名前</td>
                <td>日付</td>
                <td>タイトル</td>
                <td>課題内容</td>
                <td>更新</td>
                <td>削除</td>
    
            </tr>
            <c:forEach var="e" items="${ALL_TASKDATA}">
                <tr>
                    <td><c:out value="${e.userName}" /></td>
                    <td><c:out value="${e.taskDay}" /></td>
    
                    <td><c:out value="${e.taskTitle}" /></td>
                    <td><div class="form-container">
                            <div class="editor"></div>
                            <!-- Server側のデータを文字列としてvalueにセットする -->
                            <input type="hidden" name="contents" value="${e.task}" />
                        </div></td>
    
                    <td><a href="UpdateServlet?taskId=${ e.taskId}">更新</a></td>
                    <td><a href="DeleteServlet?taskId=${ e.taskId}">削除</a></td>
    
                </tr>
            </c:forEach>
        </table>
        <div>
            <a class="btn-square-slant" href="selectMenu.jsp">メニューへ</a> <a
                href="welcome.jsp" class="btn-square-slant">トップへ戻る</a>
        </div>
        <script type="text/javascript" src="quillcustom.js"></script>
    </body>
    </html>
```

```

    // このファイルは"quillcustom.js"です
    
    const quill = new Quill("#editor-container", {
      theme: "snow"
    });
    
    // サーバーから返ってきた値をセットする
    try {
      if (window.SERVER_TEXT && typeof window.SERVER_TEXT === "string") {
        const restoreContents = JSON.parse(window.SERVER_TEXT); // string -> jsonへ変換
        quill.setContents(restoreContents);
      }
    } catch (error) {
      console.error(error);
    }
    
    const form = document.querySelector("form");
    const contentsInput = document.querySelector("input[name=contents]");
    
    form.onsubmit = () => {
      contentsInput.value = JSON.stringify(quill.getContents());
      return true;
    };
```

```

    @import
        url(https://fonts.googleapis.com/css?family=Source+Sans+Pro:200,300,400,700)
        ;
    
    @import
        url(https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css)
        ;
    
    @import
        url(https://maxcdn.bootstrapcdn.com/font-awesome/4.1.0/css/font-awesome.min.css)
        ;
    
    * {
        margin: 0;
        padding: 0;
    }
    
    html {
        background-color: #333333
    }
    
    body {
        background-color: #333333
    }
    
    body, input, button {
        font-family: 'Source Sans Pro', sans-serif;
    }
    
    .login {
        padding: 15px;
        width: 400px;
        min-height: 400px;
        margin: 2% auto 0 auto;
    }
    
    .login .heading {
        text-align: center;
        margin-top: 1%;
    }
    
    .login .heading h2 {
        font-size: 3em;
        font-weight: 300;
        color: rgba(255, 255, 255, 0.7);
        display: inline-block;
        padding-bottom: 5px;
        text-shadow: 1px 1px 3px #23203b;
    }
    
    .login form .input-group {
        border-bottom: 1px solid rgba(255, 255, 255, 0.1);
        border-top: 1px solid rgba(255, 255, 255, 0.1);
    }
    
    .login form .input-group:last-of-type {
        border-top: none;
    }
    
    .login form .input-group span {
        background: transparent;
        min-width: 53px;
        border: none;
    }
    
    .login form .input-group span i {
        font-size: 1.5em;
        color: rgba(255, 255, 255, 0.2);
    }
    
    .login form input.form-control {
        display: block;
        width: auto;
        height: auto;
        border: none;
        outline: none;
        box-shadow: none;
        background: none;
        border-radius: 0px;
        padding: 10px;
        font-size: 1.6em;
        width: 100%;
        background: transparent;
        color: #c2b8b1;
    }
    
    .login form input.form-control:focus {
        border: none;
    }
    
    .login form button {
        margin-top: 20px;
        background: #27AE60;
        border: none;
        font-size: 1.6em;
        font-weight: 300;
        padding: 5px 0;
        width: 100%;
        border-radius: 3px;
        color: #b3eecc;
        border-bottom: 4px solid #1e8449;
    }
    
    .login form button:hover {
        background: #30b166;
        -webkit-animation: hop 1s;
        animation: hop 1s;
    }
    
    .float {
        display: inline-block;
        -webkit-transition-duration: 0.3s;
        transition-duration: 0.3s;
        -webkit-transition-property: transform;
        transition-property: transform;
        -webkit-transform: translateZ(0);
        transform: translateZ(0);
        box-shadow: 0 0 1px rgba(0, 0, 0, 0);
    }
    
    .float:hover, .float:focus, .float:active {
        -webkit-transform: translateY(-3px);
        transform: translateY(-3px);
    }
    
    /* Large Devices, Wide Screens */
    @media only screen and (max-width: 1200px) {
        .login {
            width: 600px;
            font-size: 2em;
        }
    }
    
    @media only screen and (max-width: 1100px) {
        .login {
            margin-top: 2%;
            width: 600px;
            font-size: 1.7em;
        }
    }
    /* Medium Devices, Desktops */
    @media only screen and (max-width: 992px) {
        .login {
            margin-top: 1%;
            width: 550px;
            font-size: 1.7em;
            min-height: 0;
        }
    }
    /* Small Devices, Tablets */
    @media only screen and (max-width: 768px) {
        .login {
            margin-top: 0;
            width: 500px;
            font-size: 1.3em;
            min-height: 0;
        }
    }
    /* Extra Small Devices, Phones */
    @media only screen and (max-width: 480px) {
        .login {
            margin-top: 0;
            width: 400px;
            font-size: 1em;
            min-height: 0;
        }
        .login h2 {
            margin-top: 0;
        }
    }
    /* Custom, iPhone Retina */
    @media only screen and (max-width: 320px) {
        .login {
            margin-top: 0;
            width: 200px;
            font-size: 0.7em;
            min-height: 0;
        }
    }
    
    /* ログイン成功画面 */
    .loginSuccess {
        padding: 15px;
        width: 400px;
        min-height: 400px;
        margin: 2% auto 0 auto;
    }
    
    .loginSuccess .heading h2 {
        font-size: 3em;
        font-weight: 300;
        color: rgba(255, 255, 255, 0.7);
        display: inline-block;
        padding-bottom: 5px;
        text-shadow: 1px 1px 3px #23203b;
    }
    /* メニュー画面 */
    .menu {
        padding: 15px;
        width: 400px;
        min-height: 400px;
        margin: 2% auto 0 auto;
    }
    
    .menu .heading h2 {
        font-size: 3em;
        font-weight: 300;
        color: rgba(255, 255, 255, 0.7);
        display: inline-block;
        padding-bottom: 5px;
        text-shadow: 1px 1px 3px #23203b;
    }
    
    /* トップ画面 */
    .welcome {
        padding: 15px;
        width: 500px;
        min-height: 400px;
        margin: 2% auto 0 auto;
    }
    
    .welcome .heading h2 {
        font-size: 2em;
        font-weight: 300;
        color: rgba(255, 255, 255, 0.7);
        display: inline-block;
        padding-bottom: 5px;
        text-shadow: 1px 1px 3px #23203b;
        text-align:center
    }
    
    
    /* 完了画面 */
    .success {
        padding: 15px;
        width: 400px;
        min-height: 400px;
        margin: 2% auto 0 auto;
    }
    
    .success .heading h2 {
        font-size: 3em;
        font-weight: 300;
        color: rgba(255, 255, 255, 0.7);
        display: inline-block;
        padding-bottom: 5px;
        text-shadow: 1px 1px 3px #23203b;
    }
    
    /* 課題登録・更新画面 */
    .taskD h2 {
        font-size: 3em;
        font-weight: 300;
        color: rgba(255, 255, 255, 0.7);
        display: inline-block;
        padding-bottom: 5px;
        text-shadow: 1px 1px 3px #23203b;
    
    }
    
    /* ボタン */
    .btn-square-slant {
        display: inline-block;
        position: relative;
        padding: 0.5em 1.4em;
        text-decoration: none;
        background: #30b166; /*ボタン色*/
        color: #FFF;
        border-bottom: solid 5px #36528c; /*ボタン色より暗めに*/
        border-right: solid 5px #5375bd; /*ボタン色より暗めに*/
    }
    
    .btn-square-slant:before {
        content: " ";
        position: absolute;
        bottom: -5px;
        left: -1px;
        width: 0;
        height: 0;
        border-width: 0 6px 6px 0px;
        border-style: solid;
        border-color: transparent;
        border-bottom-color: #FFF;
    }
    
    .btn-square-slant:after {
        content: " ";
        position: absolute;
        top: -1px;
        right: -5px;
        width: 0;
        height: 0;
        border-width: 0px 6px 6px 0px;
        border-style: solid;
        border-color: #FFF;
        border-bottom-color: transparent;
    }
    
    .btn-square-slant:active {
        /*ボタンを押したとき*/
        border: none;
        -webkit-transform: translate(6px, 6px);
        transform: translate(6px, 6px);
    }
    
    .btn-square-slant:active:after, .btn-square-slant:active:before {
        content: none; /*ボタンを押すと線が消える*/
    }
    
    .buttons {
        display: table;
        width: 100%;
        margin: 2% auto 0 auto;
        /* 子要素の幅の均等化 */
        table-layout: fixed;
    }
    
    .buttons a {
        margin-left: 60px;
    }
    
    /* テーブル */
    .tableD {
        width: 100%;
        border-collapse: collapse;
    }
    
    .tableD tr {
        background-color: #333333;
    }
    
    .tableD tr:last-child * {
    
    }
    
    .tableD th, table td {
        text-align: center;
        border: solid 2px #fff;
        color: white;
        padding: 10px 0;
    }
    
    /* 文字入力色 */
    input {
        color: #333333;
    }
    
    textarea {
        color: #333333;
    }
    
    .label {
        color: white; /* 文字色を白にする */
    }
```

```

    <%@ page language="java" contentType="text/html; charset=UTF-8"
        pageEncoding="UTF-8"%>
    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="UTF-8">
    <link rel="stylesheet" type="text/css" href="/TaskApp/css/common.css">
    <title>投稿画面</title>
    <script src="https://cdn.quilljs.com/1.3.6/quill.js"></script>
    <link href="https://cdn.quilljs.com/1.3.6/quill.snow.css"
        rel="stylesheet">
    <link href="https://cdn.quilljs.com/1.3.6/quill.bubble.css"
        rel="stylesheet">
    <script>
        // 1. 値はサーバーから返ってきた値をstringとして埋め込んでください
        // 2. もし復元したくない場合は以下の行をコメントアウトしてください
        //window.SERVER_TEXT = '{"ops":[{"attributes":{"underline":true,"italic":true,"bold":true},"insert":"Hello world!"},{"insert":"\\n"}]}';
    </script>
    </head>
    <body>
        <div class="taskD">
            <h2>課題タイトルと課題内容を記入してください</h2>
    
            <form action="PostServlet" method="POST" name="task_form">
                <table class="tableD">
                    <tr>
                        <td>タイトル</td>
                        <td><input type="text" name="taskTitle" size="90"
                            maxlength="40"></td>
                    </tr>
                    <tr>
                        <td>課題内容</td>
                        <td>
                            <div id="editor-container"></div> <!-- Quiil.jsのエディターの値の受け皿として定義 -->
                            <input type="hidden" name="contents" />
    
                        </td>
                    </tr>
                    <tr>
    
                        <td colspan="2"><input type="submit" value="課題登録"
                            class="btn-square-slant"></td>
                    </tr>
    
                </table>
    
            </form>
        </div>
        <script type="text/javascript" src="quillcustom.js"></script>
    </body>
    </html>
```

servlet

```

    package controller;
    
    import java.io.IOException;
    import java.sql.Date;
    
    import javax.servlet.ServletException;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import javax.servlet.http.HttpSession;
    
    import entity.AccountDTO;
    import model.Logic;
    
    /**
     * Servlet implementation class PostServlet
     */
    @WebServlet("/PostServlet")
    public class PostServlet extends HttpServlet {
        private static final long serialVersionUID = 1L;
    
        public PostServlet() {
            super();
        }
    
        protected void doGet(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
    
            response.getWriter().append("Served at: ").append(request.getContextPath());
        }
    
        protected void doPost(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
    
            request.setCharacterEncoding("UTF-8");
    
            HttpSession session = request.getSession();
    
            AccountDTO a = (AccountDTO) session.getAttribute("LOGINUSER");
    
            int inputId = a.userId;
    
            String inputTaskTitle = request.getParameter("taskTitle");
            String inputTask = request.getParameter("contents");
            Date date = new Date(System.currentTimeMillis());
    
            String move = "post.jsp";
    
            Logic postData = new Logic();
    
            postData.newTask(inputId, date, inputTaskTitle, inputTask);
    
            move = "postOK.jsp";
    
            request.getRequestDispatcher(move).forward(request, response);
    
            doGet(request, response);
        }
    
    }
    
```

[![画像の説明をここに入力](https://i.stack.imgur.com/C3xuy.png)](https://i.stack.imgur.com/C3xuy.png)
CC BY-SA 4.0
2020-06-18T03:58:28.817
67777
2022-06-18T08:06:40.637
2020-06-24T00:08:42.407
40715
40715
question
java mysql database jsp servlet
Quill.jsを使ったテキストエディターのデータをデータベースに追加し、表示する方法を教えてください。
今回の質問をコメント欄を見つつ再定義すると、「Quill.jsを利用してformでsubmitし、サーバーで保存した後に復元する方法をクライアント側でどう実装するか」と捉えます。Quillのドキュメントに[formでsubmitする方法](https://quilljs.com/playground/#form-
submit)が書いてありますが、幾分か今回の質問には適していないのでカスタマイズしたサンプルを提供します。  
また、既存のコードから作り直すと大変なので、説明に必要な十分な分だけ記述します。

```

    // このファイルは"quillcustom.js"です
    
    const quill = new Quill("#editor-container", {
      theme: "snow"
    });
    
    // サーバーから返ってきた値をセットする
    try {
      if (window.SERVER_TEXT && typeof window.SERVER_TEXT === "string") {
        const restoreContents = JSON.parse(window.SERVER_TEXT); // string -> jsonへ変換
        quill.setContents(restoreContents);
      }
    } catch (error) {
      console.error(error);
    }
    
    const form = document.querySelector("form");
    const contentsInput = document.querySelector("input[name=contents]");
    
    form.onsubmit = () => {
      contentsInput.value = JSON.stringify(quill.getContents());
      return true;
    };
```

```

    <!DOCTYPE html>
    <html lang="ja">
    
    <head>
      <script src="https://cdn.quilljs.com/1.3.6/quill.js"></script>
      <link href="https://cdn.quilljs.com/1.3.6/quill.snow.css" rel="stylesheet">
      <link href="https://cdn.quilljs.com/1.3.6/quill.bubble.css" rel="stylesheet">
      <script>
        // 1. 値はサーバーから返ってきた値をstringとして埋め込んでください
        // 2. もし復元したくない場合は以下の行をコメントアウトしてください
        window.SERVER_TEXT = '{"ops":[{"attributes":{"underline":true,"italic":true,"bold":true},"insert":"Hello world!"},{"insert":"\\n"}]}';
      </script>
    </head>
    
    <body>
      <form method="post" action="/">
        <div id="editor-container"></div>
        <!-- Quiil.jsのエディターの値の受け皿として定義 -->
        <input type="hidden" name="contents" />
        <button type="submit">送信</button>
      </form>
      <script type="text/javascript" src="./quillcustom.js"></script>
    </body>
    
    </html>
```

ポイントとしては、

  * submit時に隠し要素にQuill.jsエディタのデータを取得する
  * 取得したデータは`JSON.stringify`でテキスト化されたJSONデータとしてサーバー側に保存する
  * サーバー側はstring(VARCHAR)で保存する
  * 復元時は、`window.SERVER_TEXT`に保存されたサーバー側の文字列を直接埋め込む（テンプレートエンジンでテキストを出力するやり方と同じです）
  * `JSON.parse`は失敗する可能性があるので、try-catchでエラーハンドエリングしておく

となります。

**POST時の確認方法**

Google Chromeをお使いであれば、DevToolのNetowrkタブで`Preserve
Log`にチェックを入れて、「送信」をクリックし、送信時のデータを確認すると送られていることがわかります。

[![画像の説明をここに入力](https://i.stack.imgur.com/cz3Il.png)](https://i.stack.imgur.com/cz3Il.png)

試してみたところ、本質問のSnipet実行でも確認できるようです。

[![StackOverflowのSnipet実行でPOSされたform-
dataを確認してみた](https://i.stack.imgur.com/Bypyc.png)](https://i.stack.imgur.com/Bypyc.png)

**その他**

少し質問のコードに対して触れておくと、以下の部分で不具合があるようです。

  * `quill_1.getContent`ではなく、`quill_1.getContents()`が正しい呼び出し方
  * `JSON.parse(json_text)`の`json_text`が`undefined`の場合にexceptionを吐いて止まる

## 追記分

やりたいことを再度確認すると、form要素を複数描画したいように見えました。ここまでくると、JavaScriptがどれくらい理解して書けるかが試される部分かと思います。エディターに復元するservletからのレスポンスはこちらでは動作確認できないので、自ら埋め込んで見てください。

```

    // このファイルは"quillcustom.js"です
    
    /**
     * Quillエディターの諸々の設定を行う
     *
     * @param HTMLElement target Quillエディタを描画するElement
     * @param string | undefined defaultContents 初期値
     */
    const createQuillEditor = (target, defaultContents) => {
      const quill = new Quill(target, {
        theme: "snow",
      });
      try {
        if (defaultContents) {
          const restoreContents = JSON.parse(defaultContents); // string -> jsonへ変換
          quill.setContents(restoreContents);
        }
      } catch (error) {
        console.error(error);
      }
      return quill;
    };
    
    /**
     * containerを基準にElementに対してEventHandlerを登録する
     * @param HTMLDivElement container
     */
    const setupFormContainer = (container) => {
      const form = container.querySelector("form");
      const editor = container.querySelector(".editor");
      const contentsInput = container.querySelector("input[name=contents]");
      const quill = createQuillEditor(editor, contentsInput.value);
      form.onsubmit = () => {
        contentsInput.value = JSON.stringify(quill.getContents());
        return true;
      };
    };
    
    const initialize = () => {
      const containers = document.querySelectorAll(".form-container");
      Array.from(containers).forEach((container) => {
        setupFormContainer(container);
      });
    };
    
    initialize();
```

```

    <!DOCTYPE html>
    <html lang="ja">
    
    <head>
      <script src="https://cdn.quilljs.com/1.3.6/quill.js"></script>
      <link href="https://cdn.quilljs.com/1.3.6/quill.snow.css" rel="stylesheet">
      <link href="https://cdn.quilljs.com/1.3.6/quill.bubble.css" rel="stylesheet">
    </head>
    
    <body>
    
      <!-- BLOCK1: ここから -->
      <div class="form-container">
        <form method="post" action="/">
          <p>タイトル：<input type="text" name="taskTitle" size="90" maxlength="40"></p>
          <div class="editor"></div>
          <!-- Server側のデータはvalueにセットする -->
          <input type="hidden" name="contents" value='{"ops":[{"attributes":{"underline":true,"italic":true,"bold":true},"insert":"Hello world!"},{"insert":"\n"}]}' />
          <button type="submit">課題登録</button>
        </form>
      </div>
      <!-- BLOCK1: ここまで -->
    
      <!-- BLOCK2: ここから -->
      <div class="form-container">
        <form method="post" action="/">
          <p>タイトル：<input type="text" name="taskTitle" size="90" maxlength="40"></p>
          <div class="editor"></div>
          <!-- Server側のデータを文字列としてvalueにセットする -->
          <input type="hidden" name="contents" value='{"ops":[{"attributes":{"underline":true,"italic":true,"bold":true},"insert":"Section 2"},{"insert":"\n"}]}' />
          <button type="submit">課題登録</button>
        </form>
      </div>
      <!-- BLOCK2: ここまで -->
    
      <script type="text/javascript" src="./quillcustom.js"></script>
    </body>
    
    </html>
```

## 追記2

>
> 追記していただいたjsの内容を追加して、Block2の内容をjspファイルに書き込み、valueの部分にデータベースから取得したString型のjsonデータの内容を入れたのですが、出力されませんでした。

追加するだけではあなたの実装コードベースでは動きません。`<a href="UpdateServlet?taskId=${
e.taskId}">更新</a>`の実装を見る限り、更新をGETで行っていますが、データが送信されているようには見えません。`form`タグを利用してdataをサーバー側に送る必要があります。  
`form`タグまでの使い方はドキュメントを読んで確認してみてください。

  * <https://developer.mozilla.org/ja/docs/Learn/HTML/Forms/Sending_and_retrieving_form_data>

> Block1とBlock2は課題登録と書かれているのですが、これはデータを表示するものではないのでしょうか？

  * Block1, Block2の表現はfor-loopのループ単位として表現しましたが、伝わりにくかったかもしれないです。以下のような利用方法を想定して書きました。

```

    <c:forEach var="e" items="${ALL_TASKDATA}">
      <div class="form-container">
      <form method="post" action="/">
        <div class="editor"></div>
        <input type="hidden" name="contents" value="${e.task}" />
      </form>
      </div>
    </c:forEach>
    
```

>
> データベースにあるString型のjsonデータをBlock2のValueに入れることで、jsonデータの形が通常の文字（リッチテキスト）として表示される

回答に示した実装コードを読んでみてください。JSON.parseを利用して一度JSON.stringifyが適用された文字をJSON化した後、`setContents`を利用してQuill
Editorがリッチテキストとして表示できるようにしています。

質問内容が一番最初の頃からだいぶ肥大化しており、時間がだいぶかかってしまうので、これ以上は自分は対応できかねます。

一通り見て感じたのは純粋なHTMLを書いてformによるGET/POSTを一度試してみたほうが良いと感じました。これがデバッグできるようになってから、for-
loopで要素数を増やさなければ今後もデバッグが大変かと思います。

また、JSONのやり取りが今回必要になってきているため、JavaScriptを必ず利用する必要があり、実装難易度が上がっています。`JavaScriptの知識が全くなく`の状態からするとかなり敷居が高いので、一つ一つできる範囲で動作を確認することをおすすめします。もちろん、質問は歓迎ですが、粒度を小さくして質問を繰り返すことで理解がしやすくなるでしょう。

申し訳ないですが自分はここまでとさせていただきます。頑張ってください。
CC BY-SA 4.0
2020-06-18T09:15:32.467
67782
2020-06-22T16:12:51.783
2020-06-22T16:12:51.783
7997
7997
67777
answer