본문 바로가기
개발/JAVA

[JAVA] Spring Controller를 직접 만들어보자 (3) - 핸들러 매핑

by 상용최 2021. 1. 16.
반응형

지난편에서 Controller를 만들고 Controller의 매핑정보를 만들었다.

그렇다면 이제 실제로 매핑을 해서 페이지이동 및 결과를 돌려주는 간단한 로직을 작성해보도록 하겠다.

 

먼저 Controller에 등록되어있는 매핑정보와 return value를 수정해준다.

@RestController
public class RestTestController {

    @PostMapping("/rest/posttest")
    public String restPostMapping(){
        return "post";
    }

    @GetMapping("/rest/gettest")
    public String restGetMapping(){
        return "get";
    }

}
@Controller
public class TestController {
    public TestController() {
    }

    @GetMapping("/index")
    public String controllerGetMapping(){
        return "/index.jsp";
    }

    @GetMapping("/test")
    public String controllerPostMapping(){
        return "/test.jsp";
    }
}

 

위와같이 수정한 후 실행하게 되면 HandlerMapping 객체에서는 매핑정보를 가지고 있게된다.

그렇다면 이제 요청이 들어왔을 때 매핑시키고 결과를 돌려주는 로직을 작성 해보겠다.

 

public class ControllerFilter implements Filter {

    HandlerMapping handlerMapping = new HandlerMapping();

    @Override
    public void init(FilterConfig filterConfig) {
        handlerMapping.init();
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        String method = request.getMethod();
        String requestURI = request.getRequestURI();

        if("GET".equals(method) || "POST".equals(method)) {
            if (handlerMapping.isPageRequest(requestURI)) {
                Object invoke = handlerMapping.invoke(requestURI);
                RequestDispatcher requestDispatcher = servletRequest.getRequestDispatcher(invoke.toString());
                requestDispatcher.forward(servletRequest, servletResponse);
            } else if (handlerMapping.isApiRequest(requestURI)) {
                Object invoke = handlerMapping.invoke(requestURI);
                servletResponse.setContentType("application/json");

                try (PrintWriter writer = servletResponse.getWriter()) {
                    writer.write("{ \"result\": \"" + invoke.toString() + "\"}");
                    writer.flush();
                }
            }
        }else {
            filterChain.doFilter(servletRequest, servletResponse);
        }
    }

    @Override
    public void destroy() {
    }
}

 

우리는 현재 GET과 POST만을 지원하기에 GET과 POST가 아니라면 filterChain을 통해 다음 필터로 넘기도록 한다.

이후에 아무필터도 없다면 오류처리를 해도 좋다.

 

우리는 HandlerMapping을 통해 있는지를 검사하고 있다면 실행해서 결과를 받을 것이다.

그러기 위해 HandlerMapping Class를 아래와 같이 수정해준다.

public class HandlerMapping {

    Map<String, MethodInvoker> controller = new HashMap<>();
    Map<String, MethodInvoker> restController = new HashMap<>();

    public void init(){
        subDirList(MainApplication.class.getResource(".").getPath());
    }

    private void subDirList(String source) {
        File dir = new File(source);
        File[] fileList = dir.listFiles();

        if (fileList != null) {
            try {
                for (File file : fileList) {
                    if (file.isDirectory()) {
                        subDirList(file.getCanonicalPath());
                    } else if (file.isFile()) {
                        String path = file.getPath();

                        if (path.endsWith(".class")) {
                            int classes = path.lastIndexOf("classes");
                            String substring = path.substring(classes + 8);
                            String className = substring.split(".class")[0].replace("\\", ".");
                            Class<?> aClass = Class.forName(className);
                            if (aClass.isAnnotationPresent(Controller.class)) {
                                Method[] methods = aClass.getMethods();
                                Arrays.stream(methods)
                                        .forEach(m -> addPageHandler(aClass, m));
                            } else if (aClass.isAnnotationPresent(RestController.class)) {
                                Method[] methods = aClass.getMethods();
                                Arrays.stream(methods)
                                        .forEach(m -> addRestHandler(aClass, m));
                            }
                        }
                    }
                }
            } catch (IOException | ClassNotFoundException e) {
                e.printStackTrace();
            }
        }
    }

    private void addPageHandler(Class<?> aClass, Method m) {
        if (m.isAnnotationPresent(PostMapping.class)) {
            addPostHandler(aClass, m, MethodType.PAGE);
        } else if (m.isAnnotationPresent(GetMapping.class)) {
            addGetMapping(aClass, m, MethodType.PAGE);
        }
    }

    private void addRestHandler(Class<?> aClass, Method m) {
        if (m.isAnnotationPresent(PostMapping.class)) {
            addPostHandler(aClass, m, MethodType.POST);
        } else if (m.isAnnotationPresent(GetMapping.class)) {
            addGetMapping(aClass, m, MethodType.GET);
        }
    }

    private void addPostHandler(Class<?> aClass, Method m, MethodType methodType){
        PostMapping declaredAnnotation = m.getDeclaredAnnotation(PostMapping.class);
        String value = declaredAnnotation.value();
        MethodInvoker methodInvoker = new MethodInvoker(value, methodType, aClass, m);

        if(MethodType.PAGE.equals(methodType)){
            controller.put(value, methodInvoker);
        }else{
            restController.put(value, methodInvoker);
        }
    }

    private void addGetMapping(Class<?> aClass, Method m, MethodType methodType){
        GetMapping declaredAnnotation = m.getDeclaredAnnotation(GetMapping.class);
        String value = declaredAnnotation.value();
        MethodInvoker methodInvoker = new MethodInvoker(value, methodType, aClass, m);

        if(MethodType.PAGE.equals(methodType)){
            controller.put(value, methodInvoker);
        }else{
            restController.put(value, methodInvoker);
        }
    }

    public Object invoke(String requestURI) {
        try{
            if (isApiRequest(requestURI)) {
                MethodInvoker methodInvoker = restController.get(requestURI);
                return methodInvoker.invoke();
            } else if (isPageRequest(requestURI)) {
                MethodInvoker methodInvoker = controller.get(requestURI);
                return methodInvoker.invoke();
            }
        } catch (InvocationTargetException | IllegalAccessException | InstantiationException e) {
            e.printStackTrace();
        }

        return null;
    }

    public boolean isPageRequest(String requestUri) {
        return controller.containsKey(requestUri);
    }

    public boolean isApiRequest(String requestUri) {
        return restController.containsKey(requestUri);
    }
}

 

 

여기까지 했다면 결과를 확인해보자.

Controller 를 통해 View 페이지를 정상적으로 호출했다.

RestController를 통하여 정상적으로 json 타입으로 데이터를 반환받았다.

반응형

댓글