프로젝트 진행을 하면서 게시판 기능을 맡아서 하게 되었다. 기본적인 crud는 모두 문제가 없는데 게시판 이미지를 하나하나 관리, 삽입하는 게 꽤 번거로운 일이라서 그냥 에디터를 써보기로 했다.
네이버 에디터를 쓸까 했지만 조원 중 한 분이 다른 게시판 구현에 ckeditor를 사용했기 때문에 통일성을 위해서 ckeditor를 사용하기로 하였다.
<textarea name="text" id="editor">
</textarea>
....
<!-- 기본적인 에디터와 번역을 위한 script 이식 -->
<script src="https://cdn.ckeditor.com/ckeditor5/34.0.0/classic/ckeditor.js"></script>
<script src="https://cdn.ckeditor.com/ckeditor5/34.0.0/classic/translations/ko.js"></script>
기본적인 사용법은 매우 간단하다. cdn을 통해서 script를 받아 id를 editor로 한 textarea를 만들어주면 에디터 사용이 가능하다. 이 때 후술한 js를 통해서 이식만 해주면 된다.
Form태그를 통해서 데이터를 전송하면 데이터가 적절하게 tag로 감싸져 전송된다! 상당히 편하구먼
처음 ckeditor를 통해 이미지 전송을 하려니, 방법이 생각보다 다양했는데, (공식 매뉴얼 상에서 4가지 방법을 지원) 무료로 전송하는 방법은 Base64를 이용하는 것이었다. 나머지는 별도의 플러그인을 사용해야 하는데 이는 유료로 제공하고 있었다.
ckeditor를 통해 이미지 첨부를 하는 순간 플러그인을 적절하게 설정해주면 back에서 코드를 받아볼 수 있고 적절하게 필요한 위치에 저장을 해주면 된다.
그 후 글을 등록하면 form 태그 상에서 설정한 이미지 저장 주소로 전송이 된다.
ClassicEditor.create( document.querySelector( '#editor' ) ,{
removePlugins: [ 'Heading' ],
extraPlugins: [uploadAdapterPlugin],
language: "ko",
});
위의 코드가 id가 editor인 textarea에 에디터를 삽입하는 코드이다. extraPlugins가 이미지 업로드를 위한 플러그인을 설정하는 부분이다.
class UploadAdapter {
constructor(loader) {
this.loader = loader;
}
upload() {
return this.loader.file.then( file => new Promise(((resolve, reject) => {
this._initRequest();
this._initListeners( resolve, reject, file );
this._sendRequest( file );
})))
}
_initRequest() {
const xhr = this.xhr = new XMLHttpRequest();
xhr.open('POST', 'java를 통해 받아들이 url', true);
xhr.responseType = 'json';
}
_initListeners(resolve, reject, file) {
const xhr = this.xhr;
const loader = this.loader;
const genericErrorText = '파일을 업로드 할 수 없습니다.'
xhr.addEventListener('error', () => {reject(genericErrorText)})
xhr.addEventListener('abort', () => reject())
xhr.addEventListener('load', () => {
const response = xhr.response
if(!response || response.error) {
return reject( response && response.error ? response.error.message : genericErrorText );
}
resolve({
default: response.url //업로드된 파일 주소
})
})
}
_sendRequest(file) {
const data = new FormData()
data.append('upload',file)
this.xhr.send(data)
}
}
/**************************************/
function uploadAdapterPlugin(editor) {
editor.plugins.get('FileRepository').createUploadAdapter = (loader) => {
return new UploadAdapter(loader)
}
}
위의 extraplugins에서 설정한 플러그인에서 UploadApapter와 연결하고 어댑터를 통해서 java단에 xhr형식으로 데이터를 전송한다.
@PostMapping("/myBandImgUpload")
@ResponseBody // js상의 이미지는 MultipartHttpServletRequest 형식으로 온다.
public String image(MultipartHttpServletRequest request, HttpServletRequest req) throws Exception {
// url을 반환하기 위한 hashmap
Map<String, Object> map = new HashMap<>();
// 이미지 정보를 받아주는 코드
MultipartFile uploadFile = request.getFile("upload");
String originalFileName = uploadFile.getOriginalFilename();
String ext = originalFileName.substring(originalFileName.indexOf("."));
// 이미지 저장 경로 얻어오기 (webPath, folderPath)
String webPath = "로컬에 저장할 위치";
String folderPath = req.getSession().getServletContext().getRealPath(webPath);
// 중복방지를 위한 새로운 이름 설정
String newFileName = UUID.randomUUID() + ext;
File file = new File(folderPath + newFileName);
// 로컬에 이미지 전송
uploadFile.transferTo(file);
// map을 통해서 url을 전송해준다. 이 주소가 이후 에디터를 통해서 반환된다.
map.put("url", webPath + newFileName);
return new Gson().toJson(map);
}
이와같이 설정하면 손쉽게 이미지 첨부 이용 가능!