Merge branch 'main' into yoon
This commit is contained in:
commit
963ff1f106
8
Jenkinsfile
vendored
8
Jenkinsfile
vendored
@ -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
|
||||
'''
|
||||
}
|
||||
}
|
||||
|
||||
12
WEB-INF/web.xml
Normal file
12
WEB-INF/web.xml
Normal file
@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" id="WebApp_ID">
|
||||
<display-name>localhost</display-name>
|
||||
<welcome-file-list>
|
||||
<welcome-file>index.html</welcome-file>
|
||||
<welcome-file>index.htm</welcome-file>
|
||||
<welcome-file>index.jsp</welcome-file>
|
||||
<welcome-file>default.html</welcome-file>
|
||||
<welcome-file>default.htm</welcome-file>
|
||||
<welcome-file>default.jsp</welcome-file>
|
||||
</welcome-file-list>
|
||||
</web-app>
|
||||
@ -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;
|
||||
|
||||
@ -49,6 +59,7 @@ public class BoardController {
|
||||
private final commoncodService commoncodService;
|
||||
private final PasswordEncoder passwordEncoder;
|
||||
|
||||
|
||||
/**
|
||||
* 공지사항 목록 조회
|
||||
* @ReqMap map 요청 파라미터 (searchKeyword)
|
||||
@ -84,7 +95,6 @@ public class BoardController {
|
||||
@PostMapping
|
||||
public ApiResponse<BigInteger> createBoard(@ReqMap MapDto map) {
|
||||
|
||||
|
||||
if (map.containsKey("LOCBRDPWD") && !map.getString("LOCBRDPWD").trim().isEmpty()) { // 빈 값 체크
|
||||
String rawPassword = map.getString("LOCBRDPWD");
|
||||
String hashedPassword = passwordEncoder.encode(rawPassword);
|
||||
@ -114,6 +124,34 @@ public class BoardController {
|
||||
return ApiResponse.ok(board);
|
||||
}
|
||||
|
||||
/**
|
||||
* 파일 다운로드 API
|
||||
* @param path 파일 경로
|
||||
* @return 파일 데이터 (바이너리 응답)
|
||||
*/
|
||||
@GetMapping("/download")
|
||||
public ResponseEntity<Resource> 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();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 게시물 삭제
|
||||
* @ReqMap map 수정 데이터 (LOCBRDSEQ)
|
||||
@ -148,13 +186,20 @@ public class BoardController {
|
||||
@Member
|
||||
@ParameterCheck
|
||||
@PostMapping("/{CMNBRDSEQ}/attachments")
|
||||
public ApiResponse<String> uploadAttachment(@ReqMap MapDto map) {
|
||||
Long userId = AuthUtil.getUser().getId();
|
||||
map.put("CMNFLEREG", userId);
|
||||
boardService.insertAttachment(map);
|
||||
return ApiResponse.ok("첨부파일이 저장되었습니다.");
|
||||
public ApiResponse<String> 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)
|
||||
|
||||
@ -65,9 +65,6 @@ public interface localbordMapper {
|
||||
// 댓글/대댓글 수정
|
||||
void updateComment(MapDto map);
|
||||
|
||||
// 대댓글인지 확인
|
||||
int selectIsReply(MapDto map);
|
||||
|
||||
// 댓글에 대댓글이 있는지 확인
|
||||
int selectHasReplies(MapDto map);
|
||||
|
||||
@ -77,9 +74,6 @@ public interface localbordMapper {
|
||||
// 댓글 삭제 (대댓글 없음)
|
||||
void deleteComment(MapDto map);
|
||||
|
||||
// 대댓글 삭제
|
||||
void deleteReply(MapDto map);
|
||||
|
||||
// 댓글 비밀번호 조회
|
||||
String selectCommentPassword(int commentId);
|
||||
|
||||
|
||||
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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<MapDto> 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) {
|
||||
|
||||
@ -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<MapDto> selectSentVacationCount(MapDto map) {
|
||||
|
||||
4
src/main/resources/application-dev.yml
Normal file
4
src/main/resources/application-dev.yml
Normal file
@ -0,0 +1,4 @@
|
||||
ssl:
|
||||
key-store: classpath:localhost.p12
|
||||
key-store-password: pmgk1234
|
||||
key-store-type: PKCS12
|
||||
@ -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:
|
||||
|
||||
@ -175,13 +175,15 @@
|
||||
<!-- 댓글 삭제 -->
|
||||
<update id="updateSoftDeleteComment">
|
||||
UPDATE localcomt
|
||||
SET LOCCMTRPY = '삭제된 댓글입니다'
|
||||
SET LOCCMTRPY = '삭제된 댓글입니다',
|
||||
LOCCMTUDT = NOW()
|
||||
WHERE LOCCMTSEQ = #{LOCCMTSEQ}
|
||||
AND EXISTS (
|
||||
SELECT 1 FROM localcomt WHERE LOCCMTPNT = #{LOCCMTSEQ}
|
||||
)
|
||||
</update>
|
||||
|
||||
|
||||
<!-- 댓글 삭제 (대댓글 없을 경우) -->
|
||||
<delete id="deleteComment">
|
||||
DELETE FROM localcomt
|
||||
@ -191,19 +193,6 @@
|
||||
)
|
||||
</delete>
|
||||
|
||||
<!-- 대댓글 삭제 -->
|
||||
<delete id="deleteReply">
|
||||
DELETE FROM localcomt
|
||||
WHERE LOCCMTSEQ = #{LOCCMTSEQ}
|
||||
AND LOCCMTPNT IS NOT NULL
|
||||
</delete>
|
||||
|
||||
<!-- 대댓글인지 확인 -->
|
||||
<select id="selectIsReply" resultType="int">
|
||||
SELECT COUNT(1) FROM localcomt
|
||||
WHERE LOCCMTSEQ = #{LOCCMTSEQ} AND LOCCMTPNT IS NOT NULL
|
||||
</select>
|
||||
|
||||
<!-- 댓글에 대댓글이 있는지 확인 -->
|
||||
<select id="selectHasReplies" resultType="int">
|
||||
SELECT COUNT(1) FROM localcomt WHERE LOCCMTPNT = #{LOCCMTSEQ}
|
||||
|
||||
@ -4,8 +4,10 @@
|
||||
<sql id="searchConditions">
|
||||
<!-- 검색어 조건 -->
|
||||
<if test="searchKeyword != null and searchKeyword != ''">
|
||||
and (w.WRDDICTTL like CONCAT('%', #{searchKeyword}, '%')
|
||||
or w.WRDDICCON like CONCAT('%', #{searchKeyword}, '%'))
|
||||
and (
|
||||
REGEXP_REPLACE(w.WRDDICTTL, '\\[\\{.*?"insert":"', '') LIKE CONCAT('%', #{searchKeyword}, '%')
|
||||
OR REGEXP_REPLACE(w.WRDDICCON, '\\[\\{.*?"insert":"', '') LIKE CONCAT('%', #{searchKeyword}, '%')
|
||||
)
|
||||
</if>
|
||||
<!-- 색인표 조건 -->
|
||||
<if test="indexKeyword != null and indexKeyword != ''">
|
||||
|
||||
Loading…
Reference in New Issue
Block a user