Merge branch 'master' of https://dev.azure.com/DBNTech/SmartPortGeoInfo/_git/SmartPortGeoInfo
commit
11930b8b47
|
|
@ -0,0 +1,26 @@
|
||||||
|
package sgis.attach.entity;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.Setter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class Attach {
|
||||||
|
|
||||||
|
private long attachment_id; //파일 PK
|
||||||
|
private long postId; //게시글아이디
|
||||||
|
private String fileName; //원본 파일명
|
||||||
|
private String storedFileName; //서버에 저장된 고유 파일명 (UUID등)
|
||||||
|
private String filePath; //파일 저장 경로
|
||||||
|
private long fileSize; //파일 크기(바이트)
|
||||||
|
private String fileType; //파일 MIME(타입(e.g., image/jpeg)
|
||||||
|
private long downloadCount; //다운로드횟수
|
||||||
|
private String createdAt; //생성일
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
package sgis.attach.mapper;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
|
||||||
|
import sgis.attach.entity.Attach;
|
||||||
|
|
||||||
|
@Mapper //- Mybatis API
|
||||||
|
public interface AttachMapper {
|
||||||
|
public List<Attach> selectAttachList();
|
||||||
|
|
||||||
|
public int insertAttachList(List<Attach> attachList);
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
package sgis.attach.service;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import sgis.attach.entity.Attach;
|
||||||
|
|
||||||
|
public interface AttachService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 모든 첨부파일을 조회합니다.
|
||||||
|
* @return 모든 Attach 객체의 리스트
|
||||||
|
*/
|
||||||
|
List<Attach> getLists();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 새 게시글을 생성합니다.
|
||||||
|
* @param post 생성할 Post 객체
|
||||||
|
* @return 생성된 Post 객체 (ID 포함)
|
||||||
|
*/
|
||||||
|
boolean insertAttachList(List<Attach> attachList);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,39 @@
|
||||||
|
package sgis.attach.service.impl;
|
||||||
|
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import sgis.attach.entity.Attach;
|
||||||
|
import sgis.attach.mapper.AttachMapper;
|
||||||
|
import sgis.attach.service.AttachService;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class AttachServiceImpl implements AttachService {
|
||||||
|
|
||||||
|
private final AttachMapper attachMapper;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public AttachServiceImpl(AttachMapper attachMapper) {
|
||||||
|
this.attachMapper = attachMapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<Attach> getLists() {
|
||||||
|
return attachMapper.selectAttachList();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional
|
||||||
|
public boolean insertAttachList(List<Attach> attachList) {
|
||||||
|
int insertedRows = attachMapper.insertAttachList(attachList);
|
||||||
|
if (insertedRows > 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1,11 +1,13 @@
|
||||||
package sgis.board.controller;
|
package sgis.board.controller;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.time.OffsetDateTime; // OffsetDateTime import 추가
|
import java.time.OffsetDateTime; // OffsetDateTime import 추가
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
|
@ -15,7 +17,6 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.ui.ModelMap;
|
import org.springframework.ui.ModelMap;
|
||||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.ModelAttribute; // ModelAttribute import는 다른 메서드를 위해 유지
|
|
||||||
import org.springframework.web.bind.annotation.PathVariable;
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
import org.springframework.web.bind.annotation.PutMapping;
|
import org.springframework.web.bind.annotation.PutMapping;
|
||||||
|
|
@ -24,20 +25,23 @@ import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
import org.springframework.web.bind.annotation.ResponseBody;
|
import org.springframework.web.bind.annotation.ResponseBody;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import com.fasterxml.jackson.databind.SerializationFeature;
|
import com.fasterxml.jackson.databind.SerializationFeature;
|
||||||
|
|
||||||
import egovframework.com.cmm.util.EgovUserDetailsHelper;
|
import egovframework.com.cmm.util.EgovUserDetailsHelper;
|
||||||
|
import sgis.attach.entity.Attach;
|
||||||
|
import sgis.attach.service.AttachService;
|
||||||
import sgis.board.entity.Board;
|
import sgis.board.entity.Board;
|
||||||
import sgis.board.entity.Member;
|
import sgis.board.entity.Member;
|
||||||
import sgis.board.entity.Post; // Post entity import
|
import sgis.board.entity.Post; // Post entity import
|
||||||
import sgis.board.mapper.BoardMapper;
|
import sgis.board.mapper.BoardMapper;
|
||||||
import sgis.board.mapper.MemberMapper;
|
import sgis.board.mapper.MemberMapper;
|
||||||
import sgis.board.mapper.PostMapper;
|
|
||||||
import sgis.board.service.PostService;
|
import sgis.board.service.PostService;
|
||||||
|
import sgis.com.util.FileUploadUtil;
|
||||||
|
import sgis.com.vo.FileVO;
|
||||||
import sgis.com.vo.SessionVO;
|
import sgis.com.vo.SessionVO;
|
||||||
import sgis.com.web.BaseController;
|
import sgis.com.web.BaseController;
|
||||||
|
|
||||||
|
|
@ -50,6 +54,9 @@ public class BoardRestController extends BaseController {
|
||||||
@Autowired
|
@Autowired
|
||||||
PostService postService;
|
PostService postService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
AttachService attachService;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
MemberMapper memberMapper;
|
MemberMapper memberMapper;
|
||||||
|
|
||||||
|
|
@ -192,7 +199,8 @@ public class BoardRestController extends BaseController {
|
||||||
@RequestParam("boardContent") String content,
|
@RequestParam("boardContent") String content,
|
||||||
// Using @RequestParam(value = "parentPostId", required = false) for optionality.
|
// Using @RequestParam(value = "parentPostId", required = false) for optionality.
|
||||||
// If it comes as an empty string, it will be null.
|
// If it comes as an empty string, it will be null.
|
||||||
@RequestParam(value = "parentPostId", required = false) Long parentPostId // This is good
|
@RequestParam(value = "parentPostId", required = false) Long parentPostId/*, // This is good
|
||||||
|
@RequestParam("files") List<MultipartFile> files*/
|
||||||
) {
|
) {
|
||||||
Post newPost = new Post();
|
Post newPost = new Post();
|
||||||
newPost.setBoardCategoryId(boardCategoryId);
|
newPost.setBoardCategoryId(boardCategoryId);
|
||||||
|
|
@ -233,6 +241,41 @@ public class BoardRestController extends BaseController {
|
||||||
// PostService를 통해 게시글 생성
|
// PostService를 통해 게시글 생성
|
||||||
Post createdPost = postService.createPost(newPost);
|
Post createdPost = postService.createPost(newPost);
|
||||||
|
|
||||||
|
// 게시글 등록 성공시 파일 서버 저장 및 테이블 insert 처리
|
||||||
|
/* Date nowDate = new Date();
|
||||||
|
String strNowYyyy = new SimpleDateFormat("yyyy").format(nowDate);
|
||||||
|
String strNowMm = new SimpleDateFormat("MM").format(nowDate);
|
||||||
|
String fileUploadPath = "uploads/files/" + strNowYyyy + "/" + strNowMm + "/";
|
||||||
|
HashMap<String, Object> uploadedFileList = FileUploadUtil.multiUploadFormFile(files, fileUploadPath);
|
||||||
|
List<Attach> tbFileList = new ArrayList<Attach>(); // TB_ATTACHMENT에 insert할 리스트데이타
|
||||||
|
// 서버에 파일 업로드 처리 후, 성공하거나 util이 처리한 파일 데이타를 리턴하면 아래 수행
|
||||||
|
if (uploadedFileList != null && uploadedFileList.containsKey("file_list")) {
|
||||||
|
Object fileListObj = uploadedFileList.get("file_list");
|
||||||
|
|
||||||
|
if (fileListObj instanceof List<?>) {
|
||||||
|
List<?> fileList = (List<?>) fileListObj;
|
||||||
|
|
||||||
|
for (Object obj : fileList) {
|
||||||
|
if (obj instanceof FileVO) {
|
||||||
|
FileVO fileVO = (FileVO) obj;
|
||||||
|
Attach attach = new Attach();
|
||||||
|
attach.setPostId(createdPost.getPostId());
|
||||||
|
attach.setFileName(fileVO.getFileName()); // 원본파일명
|
||||||
|
attach.setStoredFileName(fileVO.getStoredFileName()); // 실제저장파일명
|
||||||
|
attach.setFilePath(fileVO.getFilePath()); // 파일저장경로
|
||||||
|
attach.setFileSize(fileVO.getFileSize()); // 파일크기
|
||||||
|
attach.setFileType(fileVO.getFileType()); // 파일MIME타입
|
||||||
|
|
||||||
|
tbFileList.add(attach);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tbFileList.size()>0) {
|
||||||
|
attachService.insertAttachList(tbFileList);
|
||||||
|
}
|
||||||
|
}*/
|
||||||
|
|
||||||
// 생성된 Post 객체 반환 (클라이언트에게 성공 여부 및 생성된 게시글 정보 전달)
|
// 생성된 Post 객체 반환 (클라이언트에게 성공 여부 및 생성된 게시글 정보 전달)
|
||||||
return createdPost;
|
return createdPost;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,97 @@
|
||||||
|
package sgis.com.util;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
import org.springframework.web.multipart.MultipartHttpServletRequest;
|
||||||
|
|
||||||
|
import egovframework.com.cmm.service.EgovProperties;
|
||||||
|
import sgis.com.vo.FileUtil;
|
||||||
|
import sgis.com.vo.FileVO;
|
||||||
|
import sgis.com.web.BaseController;
|
||||||
|
/**
|
||||||
|
* @FileName : FileUploadUtil.java
|
||||||
|
* @Date : 2025. 7. 15.
|
||||||
|
* @Creator :
|
||||||
|
* @Discription :
|
||||||
|
*/
|
||||||
|
public class FileUploadUtil extends BaseController {
|
||||||
|
//logger 설정
|
||||||
|
private final static Logger logger = LoggerFactory.getLogger(FileUploadUtil.class);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 파일 업로드 처리 - 다중
|
||||||
|
* @param request 파일 Multipart
|
||||||
|
* @param path uploads/files/yyyy/mm
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public static HashMap<String,Object> multiUploadFormFile(List<MultipartFile> files, String path) {
|
||||||
|
HashMap<String, Object> result = new HashMap<String, Object>(); // 최종리턴 파일목록(DB INSERT 할 데이타)
|
||||||
|
// HttpSession session = request.getSession();
|
||||||
|
MultipartHttpServletRequest mpRequest = (MultipartHttpServletRequest) files;
|
||||||
|
Iterator<String> fileNameIterator = mpRequest.getFileNames();
|
||||||
|
|
||||||
|
String uploadPath = EgovProperties.getProperty("Globals.File.StoredPath").replaceAll("/", "\\");
|
||||||
|
String uploadDirPath = "";
|
||||||
|
if(path.startsWith(System.getProperty("file.separator"))) {
|
||||||
|
uploadDirPath = path.substring(1).replaceAll("/", "\\");
|
||||||
|
} else {
|
||||||
|
uploadDirPath = path.replaceAll("/", "\\");
|
||||||
|
}
|
||||||
|
uploadDirPath = uploadPath + uploadDirPath;
|
||||||
|
String originalFileName = "";
|
||||||
|
String realFileName = "";
|
||||||
|
List<FileVO> fileList = new ArrayList<FileVO>();
|
||||||
|
while (fileNameIterator.hasNext()) {
|
||||||
|
//파일정보를 하나씩 취득한다
|
||||||
|
MultipartFile multiFile = mpRequest.getFile((String) fileNameIterator.next());
|
||||||
|
if (multiFile.getSize() > 0) {
|
||||||
|
originalFileName = multiFile.getOriginalFilename();
|
||||||
|
realFileName = FileUtil.getUniqueFileName(uploadDirPath, originalFileName);
|
||||||
|
|
||||||
|
|
||||||
|
File file = new File(uploadDirPath + realFileName);
|
||||||
|
|
||||||
|
// 디렉토리가 존재 하지 않을 경우 생성
|
||||||
|
if(!file.exists()) {
|
||||||
|
file.setExecutable(false, true);
|
||||||
|
file.setReadable(true);
|
||||||
|
file.setWritable(false, true);
|
||||||
|
file.mkdirs();
|
||||||
|
}
|
||||||
|
try{
|
||||||
|
multiFile.transferTo(file);
|
||||||
|
FileVO uploadFile = new FileVO();
|
||||||
|
// 파일 업로드 파일 원본파일명
|
||||||
|
uploadFile.setFileName(originalFileName);
|
||||||
|
// 파일 업로드 파일 저장파일명
|
||||||
|
uploadFile.setStoredFileName(realFileName);
|
||||||
|
// 파일 업로드 파일 저장경로
|
||||||
|
uploadFile.setFilePath(uploadDirPath);
|
||||||
|
// 파일 업로드 파일 크기
|
||||||
|
uploadFile.setFileSize(multiFile.getSize());
|
||||||
|
// 파일 업로드 파일 MIME타입
|
||||||
|
uploadFile.setFileType(multiFile.getContentType());
|
||||||
|
|
||||||
|
|
||||||
|
fileList.add(uploadFile);
|
||||||
|
} catch (IllegalStateException e) {
|
||||||
|
logger.error("IllegalStateException");
|
||||||
|
// 에러메세지리턴
|
||||||
|
} catch (IOException e) {
|
||||||
|
logger.error("IOException");
|
||||||
|
// 에러메세지리턴
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result.put("file_list", fileList);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,63 @@
|
||||||
|
package sgis.com.vo;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.UUID;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 파일 처리 구현 클래스
|
||||||
|
* @author
|
||||||
|
*/
|
||||||
|
public class FileUtil {
|
||||||
|
/** 로그처리 객체 */
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(FileUtil.class);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 파일 이름이 디렉토리에 이미 존재하는지 체크한다
|
||||||
|
* @param realPath 업로드디렉토리
|
||||||
|
* @param fileName 업로드파일이름
|
||||||
|
* @return String 파일이름
|
||||||
|
*/
|
||||||
|
public static String getUniqueFileName(String realPath, String fileName) {
|
||||||
|
|
||||||
|
int idx = 0;
|
||||||
|
int cnt = 1;
|
||||||
|
String temp = getSavedFileName(fileName); // 저장할 파일명 생성
|
||||||
|
File tempFile = new File(realPath+temp); // 기존에 동일한 파일명의 파일 존재하는지 체크
|
||||||
|
|
||||||
|
//이미존재하는 파일인지 확인
|
||||||
|
while(tempFile.exists()) {
|
||||||
|
//기존에 존재하면 확장자랑 파일명을 분리해서 [숫자]를 붙여서 파일이름을 짓는다
|
||||||
|
if((idx=fileName.indexOf(".")) != -1){
|
||||||
|
String left = fileName.substring(0, idx);
|
||||||
|
String right = fileName.substring(idx);
|
||||||
|
temp = left + "[" + cnt + "]" + right;
|
||||||
|
}else{
|
||||||
|
temp = fileName + "[" + cnt + "]";
|
||||||
|
}
|
||||||
|
|
||||||
|
tempFile = new File(realPath+temp);
|
||||||
|
cnt++;
|
||||||
|
}
|
||||||
|
//실제 저장될 파일이름 저장
|
||||||
|
fileName = temp;
|
||||||
|
|
||||||
|
return fileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getSavedFileName(String originalFileName) {
|
||||||
|
// 확장자 추출
|
||||||
|
String ext = "";
|
||||||
|
int lastDot = originalFileName.lastIndexOf('.');
|
||||||
|
if (lastDot != -1) {
|
||||||
|
ext = originalFileName.substring(lastDot); // .pdf, .jpg 등
|
||||||
|
}
|
||||||
|
|
||||||
|
// UUID 생성 + 확장자 붙이기
|
||||||
|
String savedFileName = UUID.randomUUID().toString() + ext;
|
||||||
|
return savedFileName;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
package sgis.com.vo;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.Setter;
|
||||||
|
import lombok.ToString;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @FileName : FileVO.java
|
||||||
|
* @Date : 2025. 7. 15.
|
||||||
|
* @Creator :
|
||||||
|
* @Discription : file vo
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@Setter
|
||||||
|
@ToString
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class FileVO implements Serializable {
|
||||||
|
//serialVersionUID
|
||||||
|
private static final long serialVersionUID = 6268293686980181848L;
|
||||||
|
private long attachment_id; //파일 PK
|
||||||
|
private String postId; //게시글아이디
|
||||||
|
private String fileName; //원본 파일명
|
||||||
|
private String storedFileName; //서버에 저장된 고유 파일명 (UUID등)
|
||||||
|
private String filePath; //파일 저장 경로
|
||||||
|
private long fileSize; //파일 크기(바이트)
|
||||||
|
private String fileType; //파일 MIME(타입(e.g., image/jpeg)
|
||||||
|
private long downloadCount; //다운로드횟수
|
||||||
|
private String createdAt; //생성일
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,76 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
|
||||||
|
<mapper namespace="sgis.attach.mapper.AttachMapper">
|
||||||
|
|
||||||
|
<select id="selectAttachList" resultType="sgis.attach.entity.Attach">
|
||||||
|
select attachment_id,
|
||||||
|
post_id,
|
||||||
|
file_name,
|
||||||
|
stored_file_name,
|
||||||
|
file_path,
|
||||||
|
file_size,
|
||||||
|
file_type,
|
||||||
|
download_count,
|
||||||
|
TO_CHAR(created_at,'YYYY-MM-DD') AS created_at
|
||||||
|
from public.tb_attachment
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<insert id="insertAttach" parameterType="sgis.attach.entity.Attach">
|
||||||
|
<selectKey keyProperty="idx" resultType="int" order="BEFORE">
|
||||||
|
SELECT COALESCE(MAX(IDX) + 1, 1) FROM TB_ATTACHMENT
|
||||||
|
</selectKey>
|
||||||
|
insert into TB_ATTACHMENT(
|
||||||
|
attachment_id
|
||||||
|
,post_id
|
||||||
|
,file_name
|
||||||
|
,stored_file_name
|
||||||
|
,file_path
|
||||||
|
,file_size
|
||||||
|
,file_type
|
||||||
|
,download_count
|
||||||
|
,created_at
|
||||||
|
) values(
|
||||||
|
#{attachment_id}
|
||||||
|
,#{post_id}
|
||||||
|
,#{file_name}
|
||||||
|
,#{stored_file_name}
|
||||||
|
,#{file_path}
|
||||||
|
,#{file_size}
|
||||||
|
,#{file_type}
|
||||||
|
,0
|
||||||
|
,NOW()
|
||||||
|
)
|
||||||
|
</insert>
|
||||||
|
|
||||||
|
<insert id="insertAttachList" parameterType="list">
|
||||||
|
<selectKey keyProperty="idx" resultType="int" order="BEFORE">
|
||||||
|
SELECT COALESCE(MAX(IDX) + 1, 1) FROM TB_ATTACHMENT
|
||||||
|
</selectKey>
|
||||||
|
insert into TB_ATTACHMENT(
|
||||||
|
attachment_id
|
||||||
|
,post_id
|
||||||
|
,file_name
|
||||||
|
,stored_file_name
|
||||||
|
,file_path
|
||||||
|
,file_size
|
||||||
|
,file_type
|
||||||
|
,download_count
|
||||||
|
,created_at
|
||||||
|
) values
|
||||||
|
<foreach item="item" collection="list" separator=",">
|
||||||
|
(
|
||||||
|
#{attachment_id}
|
||||||
|
,#{post_id}
|
||||||
|
,#{file_name}
|
||||||
|
,#{stored_file_name}
|
||||||
|
,#{file_path}
|
||||||
|
,#{file_size}
|
||||||
|
,#{file_type}
|
||||||
|
,0
|
||||||
|
,NOW()
|
||||||
|
)
|
||||||
|
</foreach>
|
||||||
|
|
||||||
|
</insert>
|
||||||
|
|
||||||
|
</mapper>
|
||||||
|
|
@ -80,6 +80,17 @@
|
||||||
<td><input type="text" id="title" name="title" class="form-control"
|
<td><input type="text" id="title" name="title" class="form-control"
|
||||||
<c:if test="${parentPostId != null && parentPostId != ''}">readonly="readonly"</c:if>/></td>
|
<c:if test="${parentPostId != null && parentPostId != ''}">readonly="readonly"</c:if>/></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th class="td-head" scope="row">파일첨부</th>
|
||||||
|
<!-- <td><input type="file" id="title" name="title" class="form-control" /></td> -->
|
||||||
|
<td>
|
||||||
|
<div id="dropZone" class="form-control p-4" style="cursor:pointer;">
|
||||||
|
<p class="text-muted">여기에 파일을 드래그 앤 드롭 하거나 클릭해서 파일 선택</p>
|
||||||
|
<input type="file" id="fileInput" multiple hidden />
|
||||||
|
<ul id="fileList" class="list-group"></ul>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th class="td-head" scope="row">내용</th>
|
<th class="td-head" scope="row">내용</th>
|
||||||
<td><textarea rows="7" class="form-control" id="boardContent" name="boardContent"></textarea></td>
|
<td><textarea rows="7" class="form-control" id="boardContent" name="boardContent"></textarea></td>
|
||||||
|
|
@ -101,7 +112,9 @@
|
||||||
<!-- 쓰기 끝 -->
|
<!-- 쓰기 끝 -->
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
let fileList = []; // 파일첨부 - 첨부된 파일 목록 포시란
|
||||||
$(document).ready(function() {
|
$(document).ready(function() {
|
||||||
|
|
||||||
var parentPostId = "${parentPostId}";
|
var parentPostId = "${parentPostId}";
|
||||||
if (parentPostId !== null && parentPostId !== '' && parentPostId !== "null") {
|
if (parentPostId !== null && parentPostId !== '' && parentPostId !== "null") {
|
||||||
// 부모글 정보 로드
|
// 부모글 정보 로드
|
||||||
|
|
@ -125,6 +138,67 @@ $(document).ready(function() {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
const $dropZone = $("#dropZone"); // 파일첨부 - 드래그앤드롭
|
||||||
|
const $fileInput = $("#fileInput"); // 파일첨부 -
|
||||||
|
const $fileListUI = $("#fileList"); // 첨부된 파일 목록 표시
|
||||||
|
|
||||||
|
// 파일 선택 창 열기
|
||||||
|
$dropZone.on("click", function () {
|
||||||
|
$fileInput.trigger("click");
|
||||||
|
});
|
||||||
|
|
||||||
|
// 드래그 오버 스타일
|
||||||
|
$dropZone.on("dragover", function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
$dropZone.addClass("dragover");
|
||||||
|
});
|
||||||
|
|
||||||
|
$dropZone.on("dragleave", function () {
|
||||||
|
$dropZone.removeClass("dragover");
|
||||||
|
});
|
||||||
|
|
||||||
|
$dropZone.on("drop", function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
$dropZone.removeClass("dragover");
|
||||||
|
const files = e.originalEvent.dataTransfer.files;
|
||||||
|
handleFiles(files);
|
||||||
|
});
|
||||||
|
|
||||||
|
$fileInput.on("change", function () {
|
||||||
|
handleFiles(this.files);
|
||||||
|
});
|
||||||
|
|
||||||
|
function handleFiles(files) {
|
||||||
|
$.each(files, function (i, file) {
|
||||||
|
// 중복 체크는 이름으로만 (간단히 처리)
|
||||||
|
if (!fileList.some(f => f.name === file.name && f.size === file.size)) {
|
||||||
|
fileList.push(file);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
renderFileList();
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderFileList() {
|
||||||
|
$fileListUI.empty();
|
||||||
|
$.each(fileList, function (index, file) {
|
||||||
|
const $li = $(`
|
||||||
|
<li class="list-group-item d-flex justify-content-between align-items-center">
|
||||||
|
<span>` + file.name + ` </span>
|
||||||
|
<b class="icon-trash remove-btn" title="삭제버튼" style="cursor:pointer;">삭제</b>
|
||||||
|
</li>
|
||||||
|
`);
|
||||||
|
$li.find(".remove-btn").on("click", function () {
|
||||||
|
removeFile(index);
|
||||||
|
});
|
||||||
|
$fileListUI.append($li);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeFile(index) {
|
||||||
|
fileList.splice(index, 1);
|
||||||
|
renderFileList();
|
||||||
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
function goList(){
|
function goList(){
|
||||||
|
|
@ -171,4 +245,49 @@ function goInsert(){
|
||||||
});
|
});
|
||||||
$(".fclear").trigger("click");
|
$(".fclear").trigger("click");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function addPost(){
|
||||||
|
var title = $("#title").val();
|
||||||
|
var content = $("#boardContent").val();
|
||||||
|
var boardCategoryId = $("#boardCategoryId").val();
|
||||||
|
var parentPostId = $("#parentPostId").val();
|
||||||
|
|
||||||
|
if(title == null || title == "" || title == 0){
|
||||||
|
alert("제목을 입력하세요");
|
||||||
|
return false;
|
||||||
|
} else if (content == null || content == "" || content == 0) {
|
||||||
|
alert("내용을 입력하세요");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append("title", title);
|
||||||
|
formData.append("content", content);
|
||||||
|
formData.append("boardCategoryId", boardCategoryId);
|
||||||
|
|
||||||
|
if (parentPostId !== null && parentPostId !== "" && parentPostId !== "null") {
|
||||||
|
formData.append("parentPostId", parentPostId);
|
||||||
|
}
|
||||||
|
// $.each(fileList, function (i, file) {
|
||||||
|
// formData.append("files", file);
|
||||||
|
// });
|
||||||
|
|
||||||
|
$.ajax({
|
||||||
|
url : "/sgis/portal/board/new.do",
|
||||||
|
type : "post",
|
||||||
|
data: formData,
|
||||||
|
contentType: false,
|
||||||
|
processData: false,
|
||||||
|
success : function(){
|
||||||
|
$("#grid").empty();
|
||||||
|
var categoryId = "${boardCategoryId}" ? "${boardCategoryId}" : "${params.boardCategoryId}";
|
||||||
|
location.href = "/sgis/portal/board-list.do?boardCategoryId=" + categoryId;
|
||||||
|
},
|
||||||
|
error : function() {
|
||||||
|
alert("error");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
$(".fclear").trigger("click");
|
||||||
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
|
||||||
|
|
@ -1806,7 +1806,12 @@ footer .newsletter input { color: #6f6f6f; letter-spacing: normal; }
|
||||||
.table .input {margin: 0px;}
|
.table .input {margin: 0px;}
|
||||||
|
|
||||||
.table textarea {display: block;}
|
.table textarea {display: block;}
|
||||||
|
.table #dropZone { height: auto !important; position: relative; }
|
||||||
|
.table #dropZone p { padding: 10px; }
|
||||||
|
.table #fileInput { position: absolute; top:0; left: 0; width: 100%; height: 100%; opacity: 0; }
|
||||||
|
.table #dropZone.dragover { background-color: #e9f7fe; border-color: #17a2b8; }
|
||||||
|
.table #dropZone #fileList { margin-bottom: 0}
|
||||||
|
.table .remove-btn { background: url(../img/common/icon/ico_btn_delete_s.png) no-repeat 10% 50%; display: inline-block; padding: 6px 0px 0px 23px; width: 60px; height: 30px; background-color: #a5d0e0; color: #fff; vertical-align: middle; border-radius: 6px;}
|
||||||
.table-content-item {min-height: 200px;}
|
.table-content-item {min-height: 200px;}
|
||||||
.table-top-btn-group {position: relative; width: 100%; display: table; box-sizing: border-box; text-align: right; padding-bottom: 20px;}
|
.table-top-btn-group {position: relative; width: 100%; display: table; box-sizing: border-box; text-align: right; padding-bottom: 20px;}
|
||||||
.table-bottom-btn-group {position: relative; width: 100%; display: table; box-sizing: border-box; text-align: right; padding-top: 20px;}
|
.table-bottom-btn-group {position: relative; width: 100%; display: table; box-sizing: border-box; text-align: right; padding-top: 20px;}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue