Skip to content

Commit 54dd332

Browse files
author
abel
committed
게시글 작성/수정시 금칙어 체크 로직 추가
1 parent 8effadb commit 54dd332

File tree

3 files changed

+92
-12
lines changed

3 files changed

+92
-12
lines changed
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package com.rest.api.annotation;
2+
3+
import com.rest.api.model.board.ParamsPost;
4+
5+
import java.lang.annotation.ElementType;
6+
import java.lang.annotation.Retention;
7+
import java.lang.annotation.RetentionPolicy;
8+
import java.lang.annotation.Target;
9+
10+
@Target({ElementType.METHOD})
11+
@Retention(RetentionPolicy.RUNTIME)
12+
public @interface ForbiddenWordCheck {
13+
String param() default "paramsPost.content";
14+
Class<?> checkClazz() default ParamsPost.class;
15+
}
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
package com.rest.api.annotation.aspect;
2+
3+
import com.rest.api.advice.exception.CForbiddenWordException;
4+
import com.rest.api.annotation.ForbiddenWordCheck;
5+
import io.micrometer.core.instrument.util.StringUtils;
6+
import org.aspectj.lang.JoinPoint;
7+
import org.aspectj.lang.annotation.Aspect;
8+
import org.aspectj.lang.annotation.Before;
9+
import org.aspectj.lang.reflect.MethodSignature;
10+
import org.springframework.stereotype.Component;
11+
12+
import java.lang.reflect.Field;
13+
import java.util.Arrays;
14+
import java.util.List;
15+
import java.util.Optional;
16+
17+
@Aspect
18+
@Component
19+
public class ForbiddenWordCheckAspect {
20+
21+
// 어노테이션이 설정된 메서드의 메인 프로세스가 시작되기전(Before)에 금칙어 체크 로직이 적용된다.
22+
@Before(value = "@annotation(forbiddenWordCheck)")
23+
public void forbiddenWordCheck(JoinPoint pjp, ForbiddenWordCheck forbiddenWordCheck) throws Throwable {
24+
// 금칙어를 체크할 메서드의 파라미터가 객체인지(객체.필드명) 일반 String인지에 따라 구분하여 처리한다.
25+
String[] param = forbiddenWordCheck.param().split("\\.");
26+
String paramName;
27+
String fieldName = "";
28+
if (param.length == 2) {
29+
paramName = param[0];
30+
fieldName = param[1];
31+
} else {
32+
paramName = forbiddenWordCheck.param();
33+
}
34+
// 메서드의 파라미터 이름으로 메서드의 몇번째 파라미터인지 구한다.
35+
Integer parameterIdx = getParameterIdx(pjp, paramName);
36+
if (parameterIdx == -1)
37+
throw new IllegalArgumentException();
38+
39+
String checkWord;
40+
// 객체내의 필드값에서 금칙어 체크 문장을 얻어내야 할 경우
41+
if (StringUtils.isNotEmpty(fieldName)) {
42+
Class<?> clazz = forbiddenWordCheck.checkClazz();
43+
Field field = clazz.getDeclaredField(fieldName);
44+
field.setAccessible(true);
45+
checkWord = (String) field.get(pjp.getArgs()[parameterIdx]);
46+
// 금칙어 체크 문장이 String형의 파라미터로 넘어오는 경우
47+
} else {
48+
checkWord = (String) pjp.getArgs()[parameterIdx];
49+
}
50+
// 체크할 문장에 금칙어가 포함되어 있는지 확인
51+
checkForbiddenWord(checkWord);
52+
}
53+
54+
// 메서드의 파라미터 이름으로 몇번째에 파라미터가 위치하는지 구함
55+
private Integer getParameterIdx(JoinPoint joinPoint, String paramName) {
56+
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
57+
String[] parameterNames = methodSignature.getParameterNames();
58+
for (int i = 0; i < parameterNames.length; i++) {
59+
String parameterName = parameterNames[i];
60+
if (paramName.equals(parameterName)) {
61+
return i;
62+
}
63+
}
64+
return -1;
65+
}
66+
67+
// 입력된 문장에 금칙어가 포함되어 있으면 Exception을 발생시킨다.
68+
private void checkForbiddenWord(String word) {
69+
List<String> forbiddenWords = Arrays.asList("개새끼", "쌍년", "씨발");
70+
Optional<String> forbiddenWord = forbiddenWords.stream().filter(word::contains).findFirst();
71+
if (forbiddenWord.isPresent())
72+
throw new CForbiddenWordException(forbiddenWord.get());
73+
}
74+
}

src/main/java/com/rest/api/service/board/BoardService.java

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import com.rest.api.advice.exception.CNotOwnerException;
55
import com.rest.api.advice.exception.CResourceNotExistException;
66
import com.rest.api.advice.exception.CUserNotFoundException;
7+
import com.rest.api.annotation.ForbiddenWordCheck;
78
import com.rest.api.common.CacheKey;
89
import com.rest.api.entity.User;
910
import com.rest.api.entity.board.Board;
@@ -60,25 +61,22 @@ public Post getPost(long postId) {
6061

6162
// 게시글을 등록합니다. 게시글의 회원UID가 조회되지 않으면 CUserNotFoundException 처리합니다.
6263
@CacheEvict(value = CacheKey.POSTS, key = "#boardName")
64+
@ForbiddenWordCheck
6365
public Post writePost(String uid, String boardName, ParamsPost paramsPost) {
6466
Board board = findBoard(boardName);
65-
// 금칙어 체크
66-
checkForbiddenWord(paramsPost.getContent());
6767
Post post = new Post(userJpaRepo.findByUid(uid).orElseThrow(CUserNotFoundException::new), board, paramsPost.getAuthor(), paramsPost.getTitle(), paramsPost.getContent());
6868
return postJpaRepo.save(post);
6969
}
7070

7171
// 게시글을 수정합니다. 게시글 등록자와 로그인 회원정보가 틀리면 CNotOwnerException 처리합니다.
7272
//@CachePut(value = CacheKey.POST, key = "#postId") 갱신된 정보만 캐시할경우에만 사용!
73+
@ForbiddenWordCheck
7374
public Post updatePost(long postId, String uid, ParamsPost paramsPost) {
7475
Post post = getPost(postId);
7576
User user = post.getUser();
7677
if (!uid.equals(user.getUid()))
7778
throw new CNotOwnerException();
7879

79-
// 금칙어 체크
80-
checkForbiddenWord(paramsPost.getContent());
81-
8280
// 영속성 컨텍스트의 변경감지(dirty checking) 기능에 의해 조회한 Post내용을 변경만 해도 Update쿼리가 실행됩니다.
8381
post.setUpdate(paramsPost.getAuthor(), paramsPost.getTitle(), paramsPost.getContent());
8482
cacheSevice.deleteBoardCache(post.getPostId(), post.getBoard().getName());
@@ -95,11 +93,4 @@ public boolean deletePost(long postId, String uid) {
9593
cacheSevice.deleteBoardCache(post.getPostId(), post.getBoard().getName());
9694
return true;
9795
}
98-
99-
public void checkForbiddenWord(String word) {
100-
List<String> forbiddenWords = Arrays.asList("개새끼", "쌍년", "씨발");
101-
Optional<String> forbiddenWord = forbiddenWords.stream().filter(word::contains).findFirst();
102-
if(forbiddenWord.isPresent())
103-
throw new CForbiddenWordException(forbiddenWord.get());
104-
}
10596
}

0 commit comments

Comments
 (0)