diff --git a/Jenkinsfile b/Jenkinsfile
index a5891cf..e306a63 100644
--- a/Jenkinsfile
+++ b/Jenkinsfile
@@ -21,8 +21,7 @@ pipeline {
echo "Tomcat is not running, skipping shutdown..."
) else (
echo "Tomcat is running, shutting down..."
- cd C:\\localhost-tomcat\\apache-tomcat-10.1.36-windows-x64\\apache-tomcat-10.1.36\\bin
- call shutdown.bat
+ net stop localtomcat
ping -n 5 127.0.0.1 > nul
)
@@ -35,9 +34,8 @@ pipeline {
ping -n 5 127.0.0.1 > nul
echo "start"
- cd /d C:\\localhost-tomcat\\apache-tomcat-10.1.36-windows-x64\\apache-tomcat-10.1.36\\bin
- call startup.bat
- ping -n 5 127.0.0.1 > nul
+ net start localtomcat
+ ping -n 8 127.0.0.1 > nul
'''
}
}
diff --git a/WEB-INF/web.xml b/WEB-INF/web.xml
new file mode 100644
index 0000000..21a5309
--- /dev/null
+++ b/WEB-INF/web.xml
@@ -0,0 +1,12 @@
+
+
+ localhost
+
+ index.html
+ index.htm
+ index.jsp
+ default.html
+ default.htm
+ default.jsp
+
+
diff --git a/src/main/java/io/company/localhost/controller/api/BoardController.java b/src/main/java/io/company/localhost/controller/api/BoardController.java
index 4daa7b2..ce62749 100644
--- a/src/main/java/io/company/localhost/controller/api/BoardController.java
+++ b/src/main/java/io/company/localhost/controller/api/BoardController.java
@@ -16,13 +16,23 @@
package io.company.localhost.controller.api;
import java.io.File;
+import java.io.IOException;
import java.math.BigInteger;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
import java.util.ArrayList;
+import java.util.Base64;
import java.util.List;
+import org.springframework.core.io.Resource;
+import org.springframework.core.io.UrlResource;
+import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
import com.github.pagehelper.PageInfo;
@@ -48,6 +58,7 @@ public class BoardController {
private final localbordService boardService;
private final commoncodService commoncodService;
private final PasswordEncoder passwordEncoder;
+
/**
* 공지사항 목록 조회
@@ -84,7 +95,6 @@ public class BoardController {
@PostMapping
public ApiResponse createBoard(@ReqMap MapDto map) {
-
if (map.containsKey("LOCBRDPWD") && !map.getString("LOCBRDPWD").trim().isEmpty()) { // 빈 값 체크
String rawPassword = map.getString("LOCBRDPWD");
String hashedPassword = passwordEncoder.encode(rawPassword);
@@ -113,6 +123,34 @@ public class BoardController {
return ApiResponse.ok(board);
}
+
+ /**
+ * 파일 다운로드 API
+ * @param path 파일 경로
+ * @return 파일 데이터 (바이너리 응답)
+ */
+ @GetMapping("/download")
+ public ResponseEntity downloadFile(@RequestParam String path) {
+ try {
+ Path filePath = Paths.get(path).normalize();
+ Resource resource = new UrlResource(filePath.toUri());
+
+ if (!resource.exists() || !resource.isReadable()) {
+ return ResponseEntity.status(HttpStatus.NOT_FOUND).body(null);
+ }
+
+ String contentType = Files.probeContentType(filePath);
+ String fileName = filePath.getFileName().toString();
+
+ return ResponseEntity.ok()
+ .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + fileName + "\"")
+ .header(HttpHeaders.CONTENT_TYPE, contentType != null ? contentType : "application/octet-stream")
+ .body(resource);
+
+ } catch (IOException e) {
+ return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
+ }
+ }
/**
* 게시물 삭제
@@ -148,13 +186,20 @@ public class BoardController {
@Member
@ParameterCheck
@PostMapping("/{CMNBRDSEQ}/attachments")
- public ApiResponse uploadAttachment(@ReqMap MapDto map) {
- Long userId = AuthUtil.getUser().getId();
- map.put("CMNFLEREG", userId);
- boardService.insertAttachment(map);
- return ApiResponse.ok("첨부파일이 저장되었습니다.");
+ public ApiResponse uploadAttachment(@ReqMap MapDto map, @RequestParam("file") MultipartFile file) {
+ try {
+ Long userId = AuthUtil.getUser().getId();
+ map.put("CMNFLEREG", userId);
+
+ boardService.insertAttachment(map, file);
+
+ return ApiResponse.ok("첨부파일이 저장되었습니다.");
+ } catch (Exception e) {
+ return ApiResponse.ok("첨부파일 저장 실패: " + e.getMessage());
+ }
}
+
/**
* 게시물, 댓글 좋아요/싫어요 추가
* @ReqMap map 데이터 (LOCCMTSEQ, MEMBERSEQ, LOCGOBGOD, LOCGOBBAD, LOCBRDSEQ)
diff --git a/src/main/java/io/company/localhost/mapper/localbordMapper.java b/src/main/java/io/company/localhost/mapper/localbordMapper.java
index 053345c..36d5e72 100644
--- a/src/main/java/io/company/localhost/mapper/localbordMapper.java
+++ b/src/main/java/io/company/localhost/mapper/localbordMapper.java
@@ -65,9 +65,6 @@ public interface localbordMapper {
// 댓글/대댓글 수정
void updateComment(MapDto map);
- // 대댓글인지 확인
- int selectIsReply(MapDto map);
-
// 댓글에 대댓글이 있는지 확인
int selectHasReplies(MapDto map);
@@ -76,9 +73,6 @@ public interface localbordMapper {
// 댓글 삭제 (대댓글 없음)
void deleteComment(MapDto map);
-
- // 대댓글 삭제
- void deleteReply(MapDto map);
// 댓글 비밀번호 조회
String selectCommentPassword(int commentId);
diff --git a/src/main/java/io/company/localhost/service/FileService.java b/src/main/java/io/company/localhost/service/FileService.java
index 13a7fdc..92f6138 100644
--- a/src/main/java/io/company/localhost/service/FileService.java
+++ b/src/main/java/io/company/localhost/service/FileService.java
@@ -34,6 +34,9 @@ public class FileService {
@Value("${filePath.profile}")
private String uploadPath;
+ @Value("${filePath.boardfile}")
+ private String boardFilePath;
+
/**
* 파일 업로드
*
@@ -65,4 +68,37 @@ public class FileService {
throw new RuntimeException("파일 업로드 실패: " + e.getMessage());
}
}
+
+ /**
+ * 게시판 파일 업로드
+ *
+ * @param file
+ * @return
+ * @throws RuntimeException
+ */
+ public String boardUploadFile(MultipartFile file) {
+ try {
+ System.out.println(file);
+ // 원본 파일명
+ String originalFilename = file.getOriginalFilename();
+ // 파일 확장자
+ String extension = FilenameUtils.getExtension(originalFilename);
+ // UUID를 사용하여 고유한 파일명 생성
+ String newFilename = UUID.randomUUID().toString() + "." + extension;
+
+ // 최종 저장 경로 생성 (기본경로 + 파일명)
+ Path targetPath = Paths.get(boardFilePath, newFilename);
+ // 저장될 디렉토리가 없는 경우 생성
+ Files.createDirectories(targetPath.getParent());
+
+ // 동일 파일명이 있을 경우 덮어쓰기
+ Files.copy(file.getInputStream(), targetPath, StandardCopyOption.REPLACE_EXISTING);
+
+ // 저장된 파일의 상대 경로 반환
+ return targetPath.toString();
+
+ } catch (IOException e) {
+ throw new RuntimeException("파일 업로드 실패: " + e.getMessage());
+ }
+ }
}
\ No newline at end of file
diff --git a/src/main/java/io/company/localhost/service/localbordService.java b/src/main/java/io/company/localhost/service/localbordService.java
index e747a7c..5b71d72 100644
--- a/src/main/java/io/company/localhost/service/localbordService.java
+++ b/src/main/java/io/company/localhost/service/localbordService.java
@@ -15,11 +15,16 @@
package io.company.localhost.service;
import java.math.BigInteger;
+import java.nio.file.Path;
+import java.nio.file.Paths;
import java.util.List;
import java.util.UUID;
import io.company.localhost.utils.BlobUtil;
+import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.multipart.MultipartFile;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
@@ -36,6 +41,7 @@ import lombok.RequiredArgsConstructor;
@RequiredArgsConstructor
public class localbordService {
private final localbordMapper boardMapper;
+ private final FileService fileService;
private static final long MAX_FILE_SIZE = 5 * 1024 * 1024; // 5MB
public List selectNotices(MapDto map) {
@@ -78,14 +84,15 @@ public class localbordService {
return (BigInteger) map.get("LOCBRDSEQ");
}
- public void insertAttachment(MapDto map) {
+ public void insertAttachment(MapDto map, MultipartFile file) {
String boardSeqStr = (String) map.get("CMNBRDSEQ");
Long boardSeq = Long.parseLong(boardSeqStr);
map.put("CMNBRDSEQ", boardSeq);
String newFilename = UUID.randomUUID().toString();
map.put("CMNFLENAM", newFilename);
-
+ String Path = fileService.boardUploadFile(file);
+ map.put("CMNFLEPAT", Path);
boardMapper.insertAttachment(map);
}
@@ -166,24 +173,17 @@ public class localbordService {
}
public void deleteComment(MapDto map) {
- // 댓글이 대댓글인지 확인
- boolean isReply = boardMapper.selectIsReply(map) > 0;
+ // 댓글이 대댓글이 있는지 확인
+ boolean hasReplies = boardMapper.selectHasReplies(map) > 0;
- if (isReply) {
- // 대댓글이면 바로 삭제
- boardMapper.deleteReply(map);
+ if (hasReplies) {
+ // 대댓글이 있는 경우, '삭제된 댓글입니다.'로 변경 (소프트 삭제)
+ boardMapper.updateSoftDeleteComment(map);
} else {
- // 댓글에 대댓글이 있는지 확인
- boolean hasReplies = boardMapper.selectHasReplies(map) > 0;
-
- if (hasReplies) {
- // 대댓글이 있는 경우, '삭제된 댓글입니다.'로 변경 (소프트 삭제)
- boardMapper.updateSoftDeleteComment(map);
- } else {
- // 대댓글이 없는 경우, 완전 삭제
- boardMapper.deleteComment(map);
- }
+ // 대댓글이 없는 경우, 완전 삭제
+ boardMapper.deleteComment(map);
}
+
}
public String selectCommentPassword(int commentId) {
diff --git a/src/main/java/io/company/localhost/service/localvacaService.java b/src/main/java/io/company/localhost/service/localvacaService.java
index 5b6dd27..616f91e 100644
--- a/src/main/java/io/company/localhost/service/localvacaService.java
+++ b/src/main/java/io/company/localhost/service/localvacaService.java
@@ -218,30 +218,38 @@ public class localvacaService {
return emp;
}).collect(Collectors.toList());
}
-
- /**
- * 총 연차 계산 로직
- */
- private int procCalculateTotalVacation(LocalDate hireDate) {
- LocalDate today = LocalDate.now();
+ /**
+ * 총 연차 계산 로직
+ */
+ public int procCalculateTotalVacation(LocalDate hireDate) {
+ LocalDate today = LocalDate.now(); // 현재 날짜
int yearsWorked = hireDate.until(today).getYears();
+ int hireMonth = hireDate.getMonthValue();
- // 🔹 1년 미만: 연간 12개 지급
+ // 🔹 1년 미만: 입사한 월을 고려하여 연차 개수 계산
if (yearsWorked < 1) {
- return 12;
+ return 12 - hireMonth;
+ } else {
+ int totalVacation = 12 - hireMonth; // 1년 미만 사용하고 남은 연차 수 반영
+ LocalDate nextIncreaseDate = hireDate.plusYears(1).withMonth(hireMonth).withDayOfMonth(1);
+
+ // 🔹 매년 입사월에 15개 지급
+ while (!nextIncreaseDate.isAfter(today)) {
+ totalVacation += 15;
+ nextIncreaseDate = nextIncreaseDate.plusYears(1);
+ }
+
+ // 🔹 입사년도 2년마다 입사월에 15개에서 1개씩 추가 지급
+ LocalDate additionalIncreaseDate = hireDate.plusYears(2).withMonth(hireMonth).withDayOfMonth(1);
+ int extraIncrease = 1;
+ while (!additionalIncreaseDate.isAfter(today)) {
+ totalVacation += extraIncrease;
+ additionalIncreaseDate = additionalIncreaseDate.plusYears(2);
+ extraIncrease++; // 2년마다 1개씩 증가
+ }
+
+ return totalVacation;
}
-
- // 🔹 1년 이상 기본 15개
- int totalVacation = 15;
- LocalDate nextIncreaseDate = hireDate.plusYears(2).withMonth(1).withDayOfMonth(1);
-
- // 🔹 2년마다 1개 추가
- while (nextIncreaseDate.isBefore(today) || nextIncreaseDate.isEqual(today)) {
- totalVacation += 1;
- nextIncreaseDate = nextIncreaseDate.plusYears(2);
- }
-
- return totalVacation;
}
public List selectSentVacationCount(MapDto map) {
diff --git a/src/main/resources/application-dev.yml b/src/main/resources/application-dev.yml
new file mode 100644
index 0000000..57b8c7e
--- /dev/null
+++ b/src/main/resources/application-dev.yml
@@ -0,0 +1,4 @@
+ ssl:
+ key-store: classpath:localhost.p12
+ key-store-password: pmgk1234
+ key-store-type: PKCS12
diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml
index 7060bfc..911b646 100644
--- a/src/main/resources/application.yml
+++ b/src/main/resources/application.yml
@@ -82,10 +82,6 @@ server:
secure: true
same-site: NONE
partitioned: true
- ssl:
- key-store: classpath:localhost.p12
- key-store-password: pmgk1234
- key-store-type: PKCS12
logging:
level:
diff --git a/src/main/resources/mapper/localbordMapper.xml b/src/main/resources/mapper/localbordMapper.xml
index 968b4f7..0c9ea8a 100644
--- a/src/main/resources/mapper/localbordMapper.xml
+++ b/src/main/resources/mapper/localbordMapper.xml
@@ -175,12 +175,14 @@
+
-
-
-
- DELETE FROM localcomt
- WHERE LOCCMTSEQ = #{LOCCMTSEQ}
- AND LOCCMTPNT IS NOT NULL
-
-
-
-