본문 바로가기
Spring

스프링 비속어 필터링 인터셉터

by windy7271 2024. 2. 9.
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

 

반응형

댓글