Статьи

AJAX с CKEditor в весенней загрузке

1. Обзор

В этой статье мы рассмотрим, как использовать CKEditor с Spring Boot . В этом руководстве мы будем импортировать XML-документ с многочисленными данными, запрограммировать возможность загрузки набора данных в экземпляр CKEditor с помощью запроса GET и выполнить запрос POST для сохранения данных CKEditor.

Технологии, которые мы будем использовать, включают MongoDB, Thymeleaf и Spring Batch.

Полный исходный код этого руководства доступен на Github .

2. Что такое CKEditor?

CKEditor — это редактор содержимого «WYSIWYG», основанный на браузере (WYSIWYG) . Целью CKEditor является привнесение в веб-интерфейс общих функций текстового процессора, которые можно найти в приложениях для редактирования на компьютере, таких как Microsoft Word и OpenOffice.

CKEditor имеет множество функций для конечных пользователей в отношении пользовательского интерфейса, вставки контента, создания контента и многого другого.

Существуют разные версии CKEditor, но для этого урока мы используем CKEditor 4. Чтобы увидеть демонстрацию, посетите: https://ckeditor.com/ckeditor-4/

3. Документ XML

Как уже упоминалось, мы загружаем XML-документ в этом приложении. Данные XML будут вставлены в базу данных и использованы для остальной части учебника.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
<?xml version="1.0"?>
<Music xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" id="MUS-1" style="1.1">
<status date="2017-11-07">draft</status>
 <title xmlns:xhtml="http://www.w3.org/1999/xhtml" >Guide to Music I Like - No Specific Genre</title>
  <description xmlns:xhtml="http://www.w3.org/1999/xhtml" >This guide presents a catalog of music that can be found on Spotify.
    <html:br xmlns:html="http://www.w3.org/1999/xhtml"/>
    <html:br xmlns:html="http://www.w3.org/1999/xhtml"/>
    This is a very small sample of music found on Spotify and is no way to be considered comprehensive.
    </description>
    <songs>
    <song>
    <artist>
    Run the Jewels
    </artist>
    <song-title>Legend Has It</song-title>
    </song>
    <song>
    <artist>
    Kendrick Lamar
    </artist>
    <song-title>ELEMENT.</song-title>
    </song>
    <song>
    <artist>
    Weird Al Yankovic
    </artist>
    <song-title>NOW That's What I Call Polka!</song-title>
    </song>
    <song>
    <artist>
    Eiffel 65
    </artist>
    <song-title>Blue (Da Ba Dee) - DJ Ponte Ice Pop Radio</song-title>
    </song>
    <song>
    <artist>
    YTCracker
    </artist>
    <song-title>Hacker Music</song-title>
    </song>
    <song>
    <artist>
    MAN WITH A MISSION
    </artist>
    <song-title>
    Raise Your Flag
    </song-title>
    </song>
    <song>
    <artist>
    GZA, Method Man
    </artist>
    <song-title>
    Shadowboxin'
    </song-title>
    </song>
    </songs>
</Music>

4. Модель

Для приведенного выше XML-кода мы можем смоделировать песню следующим образом:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
public class SongModel {
    @Id
    private String id;
    @Indexed
    private String artist;
    @Indexed
    private String songTitle;
    @Indexed
    private Boolean updated;
      
    public Boolean getUpdated() {
        return updated;
    }
    public void setUpdated(Boolean updated) {
        this.updated = updated;
    }
    public String getArtist() {
        return artist;
    }
    public void setArtist(String artist) {
        this.artist = artist;
    }
    public String getSongTitle() {
        return songTitle;
    }
    public void setSongTitle(String songTitle) {
        this.songTitle = songTitle;
    }
      
    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
      
    @JsonCreator
    public SongModel(
        @JsonProperty("artist") String artist,
        @JsonProperty("song-title") String songTitle){
        this.artist = artist;
        this.songTitle = songTitle;
    }
   
    @Override
    public String toString() {
      return "Person [id=" + id + ", artist=" + artist + ", song-title=" + songTitle + "]";
    }
  
}

Для нашего приложения мы будем различать неизмененную песню и песню, которая была изменена в CKEditor с отдельной моделью и репозиторием.

Давайте теперь определим, что такое обновленная песня:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
public class UpdatedSong {
      
    @Id
    private String id;
    @Indexed
    private String artist;
    @Indexed
    private String songTitle;
    @Indexed
    private String html;
    @Indexed
    private String sid;
      
    public String getSid() {
        return sid;
    }
    public void setSid(String sid) {
        this.sid = sid;
    }
      
    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
    public String getArtist() {
        return artist;
    }
    public void setArtist(String artist) {
        this.artist = artist;
    }
    public String getSongTitle() {
        return songTitle;
    }
    public void setSongTitle(String songTitle) {
        this.songTitle = songTitle;
    }
    public String getHtml() {
        return html;
    }
    public void setHtml(String html) {
        this.html = html;
    }
  
}

5. Загрузка и обработка файлов

Поскольку эта статья посвящена CKEditor и AJAX, мы не будем вдаваться в подробности о загрузке и обработке файлов в Spring Batch. Мы подробно рассмотрели этот процесс в следующих постах:

6. Установка данных для CKEditor — GET Request

Наша цель — извлечь данные для отдельной песни и отобразить эти данные в CKEditor. Необходимо решить две проблемы: получить данные для отдельной песни и отобразить их в CKEditor.

6.1 Клиентский код

В view.html мы используем таблицу в Thymeleaf для перебора каждой песни в репозитории Song. Чтобы получить данные с сервера для конкретной песни, мы передаем идентификатор песни в функцию.

Вот фрагмент кода, который отвечает за вызов функции, которая получает данные с сервера и впоследствии устанавливает данные для экземпляра CKEditor :

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
<table class="table datatable">
<thead>
<tr>
<th>Artist</th>
<th>Song Title</th>
<th>Load</th>
</tr>
</thead>
<tbody>
<tr th:each="songList : ${songList}">
<td th:text="${songList.artist}">Text ...</td>
<td th:text="${songList.songTitle}">Text ...</td>
<td><button th:onclick="|getSong('${songList.id}')|" id="button" class="btn btn-primary btn-condensed">
<i class="glyphicon glyphicon-folder-open"></i>
</button></td>
</tr>
</tbody>
</table>

Как мы видим, идентификатор Song необходим для того, чтобы мы могли получить данные.

В функции getSong мы используем отложенное обещание, чтобы гарантировать, что данные установлены после запроса GET:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
function getSong(song) {
    $.ajax({
        url : "/api/show/?sid=" + song,
        type : 'GET',
        dataType : 'text'
    }).then(function(data) {
        var length = data.length-2;
        var datacut = data.slice(9,length);
        CKEDITOR.instances.content.setData(datacut);
  
    });
  
    $("#form").attr("action", "/api/save/?sid=" + song);
  
};

6.2 Серверный код

getSong принимает параметр с именем sid , который обозначает идентификатор песни. sid также является переменной пути в @GetMapping . Мы рассматриваем sid как String, потому что это идентификатор песни из MongoDB.

Мы проверяем, была ли песня изменена, и если это так, мы получаем соответствующую сущность ОбновленоSong . Если нет, мы относимся к Песне по-другому. В конечном итоге мы возвращаем простой POJO со строкой для данных с именем ResponseModel , однако:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
@GetMapping(value={"/show/","/show/{sid}"})
public ResponseEntity<?> getSong(@RequestParam String sid, Model model){
    ResponseModel response = new ResponseModel();
    System.out.println("SID :::::" + sid);
    ArrayList<String> musicText = new ArrayList<String>();
    if(sid!=null){
        String sidString = sid;
        SongModel songModel = songDAO.findOne(sidString);
        System.out.println("get status of boolean during get ::::::" + songModel.getUpdated());
        if(songModel.getUpdated()==false ){
              
            musicText.add(songModel.getArtist());
            musicText.add(songModel.getSongTitle());
            String filterText = format.changeJsonToHTML(musicText);
            response.setData(filterText);
              
        } else if(songModel.getUpdated()==true){
            UpdatedSong updated = updatedDAO.findBysid(sidString);
            String text = updated.getHtml();
            System.out.println("getting the updated text ::::::::" + text);
            response.setData(text);
        }
          
    }
  
    model.addAttribute("response", response);
      
    return ResponseEntity.ok(response);
}

ResponseModel — очень простой POJO, как уже упоминалось:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
public class ResponseModel {
    private String data;
      
    public ResponseModel(){
              
    }
      
    public ResponseModel(String data){
            this.data = data;
    }
  
    public String getData() {
            return data;
    }
  
    public void setData(String data) {
            this.data = data;
    }
}

7. Сохранение данных CKEditor — запрос POST

Размещение данных не является большой проблемой; однако, гарантируя, что данные обрабатываются надлежащим образом, может быть.

7.1 Код на стороне клиента

Поскольку экземпляр CKEditor является текстовой областью внутри формы, мы можем вызвать функцию при отправке формы:

01
02
03
04
05
06
07
08
09
10
$(document)
.ready(
function() {
  
// SUBMIT FORM
$("#form").submit(function(event) {
// Prevent the form from submitting via the browser.
event.preventDefault();
ajaxPost();
});

ajaxPost () извлекает текущие данные в CKEditor и устанавливает их в переменную formData :

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
function ajaxPost() {
  
// PREPARE FORM DATA
var formData = CKEDITOR.instances.content
.getData();
  
// DO POST
$
.ajax({
type : "POST",
contentType : "text/html",
url : $("#form").attr("action"),
data : formData,
dataType : 'text',
success : function(result) {
  
$("#postResultDiv")
.html(
"
  
"
+ "Post Successfully! "
+ "
  
");
  
console.log(result);
},
error : function(e) {
alert("Error!")
console.log("ERROR: ", e);
}
});
  
}
  
})

Важно отметить:

  • contentType — это «text / html»
  • dataType — это «текст»

Наличие неправильного contentType или dataType может привести к ошибкам или искаженным данным.

7.2 Серверный код

Мы указали в нашем contentType для запроса POST, что медиатип является «text / html» . Нам нужно указать в нашем отображении, что это будет использовано. Поэтому мы добавляем потребляемый = MediaType.TEXT_HTML_VALUE с нашим @PostMapping .

Области для нас, чтобы отметить, включают в себя:

  • @RequestBody String body отвечает за установку тела переменной для содержимого нашего запроса
  • Мы снова возвращаем ResponseModel , простой POJO, описанный ранее, который содержит наши данные
  • Мы рассматриваем ранее измененную SongModel отличную от той, которая не была изменена ранее

Также, как и запрос GET, sid позволяет нам иметь дело с правильной песней:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
@PostMapping(value={"/save/","/save/[sid]"}, consumes = MediaType.TEXT_HTML_VALUE)
   public @ResponseBody ResponseModel saveSong( @RequestBody String body, @RequestParam String sid){
       ResponseModel response = new ResponseModel();
       response.setData(body);
       SongModel oldSong = songDAO.findOne(sid);
       String songTitle = oldSong.getSongTitle();
       String artistName = oldSong.getArtist();
       if(oldSong.getUpdated() == false){
           UpdatedSong updatedSong = new UpdatedSong();
           updatedSong.setArtist(artistName);
           updatedSong.setSongTitle(songTitle);
           updatedSong.setHtml(body);
           updatedSong.setSid(sid);
           oldSong.setUpdated(true);
           songDAO.save(oldSong);
           updatedDAO.insert(updatedSong);
           System.out.println("get status of boolean during post :::::" + oldSong.getUpdated());
       }else{
           UpdatedSong currentSong = updatedDAO.findBysid(sid);
           currentSong.setHtml(body);
           updatedDAO.save(currentSong);
       }       
         
       return response;
   }

8. Демо

Мы посещаем localhost: 8080 :

Мы загружаем предоставленный файл music-example.xml :

Нажимаем «Загрузить» для песни:

Добавляем контент и нажимаем «Сохранить»:

Если вы вернетесь к сохраненному содержимому, вы можете увидеть «\ n» для разрывов строк. Пока что обсуждение этого выходит за рамки данного руководства.

9. Вывод

В этом руководстве мы рассмотрели, как загружать данные с помощью GET-запроса с идентификатором объекта, устанавливать для данных экземпляр CKEditor и сохранять данные CKEditor обратно в базу данных с помощью запроса POST. Есть дополнительный код, такой как использование двух разных сущностей для данных (исходная и измененная версия), который не нужен, но, надеюсь, поучителен.

Полный код можно найти на Github .

Опубликовано на Java Code Geeks с разрешения Майкла Гуда, партнера нашей программы JCG . Смотреть оригинальную статью здесь: AJAX с CKEditor в Spring Boot

Мнения, высказанные участниками Java Code Geeks, являются их собственными.