728x90
반응형
얼마전 포스팅을 할 때 비속어를 사용하면 * 표시로 바꾸게 개발을 해 보았습니다.
service 단에서 처리하는것 보다 인터셉터로 구현하는게 더 효율적이라 생각하여 Intercepter를 사용했습니다.
만약 "시발" 이 들어오면 ** 으로 출력되고, "시1발" 등 구분자를 사용햇을때도 ** 로 표시되게 했습니다.
1.BadWords
interface BadWords {
String[] koreaWord1 = {
"씨발", "병신", "ㅅㅂ", "ㅂㅅ", "닥쳐", "새끼", "시발", "개시발", "개씨발", "년", "년아", "개같은", "애미", "애비","naver","daum","google","com","net",
"네이버","다음","구글"
};
}
나쁜 단어들 담은 인터페이스를 선언 해 주고요 저는 네이버 다음 구글은 홍보같은걸 못하게 하려고 담았습니다.
2. BadWordFiltering
@Component
public class BadWordFiltering extends HashSet<String> implements BadWords {
private String substituteValue = "*";
public BadWordFiltering() {
addAll(List.of(koreaWord1));
}
public BadWordFiltering(String substituteValue) {
this.substituteValue = substituteValue;
}
public String pre_change(String text) {
Pattern pattern = Pattern.compile("[ㄱ-ㅎㅏ-ㅣ가-힣a-zA-Z\\s]");
Matcher matcher = pattern.matcher(text);
StringBuilder filteredTextBuilder = new StringBuilder();
while (matcher.find()) {
filteredTextBuilder.append(matcher.group());
}
return filteredTextBuilder.toString();
}
public String change(String text) {
for (String badWord : this) {
// 대소문자를 무시하고 정규 표현식을 만듭니다.
Pattern pattern = Pattern.compile("(?i)" + Pattern.quote(badWord));
Matcher matcher = pattern.matcher(text);
while (matcher.find()) {
int start = matcher.start();
int end = matcher.end();
String sub = this.substituteValue.repeat(end - start);
text = text.substring(0, start) + sub + text.substring(end);
}
}
return text;
}
// badWordFiltering.check(contents)를 호출하면
// 내부적으로 HashSet에 있는 나쁜 단어 목록을 확인하여 주어진 텍스트(contents)에
// 해당 단어가 포함되어 있는지 여부를 판단
public boolean check(String text) {
return stream().anyMatch(text::contains);
}
}
pre_change 는 content가 왔을때 공백도 제거하기 위해서 사용했습니다.
change 는 텍스트에서 욕설을 찾는것입니다.
3. BadWordIntercpeter
@Component
public class BadWordIntercepter implements HandlerInterceptor {
private final BadWordFiltering badWordFiltering;
public BadWordIntercepter(BadWordFiltering badWordFiltering) {
this.badWordFiltering = badWordFiltering;
}
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if (handler != null && handler instanceof HandlerMethod) {
HandlerMethod hm = (HandlerMethod) handler;
RequestMethod[] methods = hm.getMethodAnnotation(RequestMapping.class).method();
if (Arrays.asList(methods).contains(RequestMethod.POST)) {
String contents = badWordFiltering.pre_change(request.getParameter("contents"));
if (contents != null) {
contents = badWordFiltering.pre_change(contents);
if (badWordFiltering.check(contents)) {
contents = badWordFiltering.change(contents);
request.setAttribute("filteredContents", contents);
}
}
}
}
return true;
}
}
4. intercepter 등록
@Configuration
public class WebConfig implements WebMvcConfigurer {
private final BadWordFiltering badWordFiltering;
public WebConfig(BadWordFiltering badWordFiltering) {
this.badWordFiltering = badWordFiltering;
}
@Bean
public PasswordEncoder makePassword() {
return PasswordEncoderFactories.createDelegatingPasswordEncoder();
}
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new BadWordIntercepter(badWordFiltering))
.addPathPatterns("/post/create") // 인터셉터를 적용할 경로 패턴
.excludePathPatterns("/css/**", "/fonts/**")
;
}
}
post/create 가 Getmapping , Postmapping 둘 다 있어서.
인터셉터에서 Post Maping일때 메소드가 실행하게 만들어줍니다.
바뀐 contents를 filteredContents에 담아서 Controlelr로 넘겨줍니다.
@PostMapping("/post/create")
public String postSave(Model model, PostCreateReqDto postCreateReqDto, HttpSession httpSession, HttpServletRequest httpServletRequest) {
String filteredContents = (String) httpServletRequest.getAttribute("filteredContents");
System.out.println("filteredContents = " + filteredContents);
if (filteredContents != null) {
postCreateReqDto.setContents(filteredContents);
}
postSave에 HttpServletRequest를 추가 해준후에 filteredContents를 받아주고,
filteredContents null 이면 욕설없는 contents이고 그렇지 않으면 Dto에 담아줍니다.
케이스 1
케이스 2
반응형
댓글