참여링크 : http://onoffmix.com/event/19279

다른 분들과 함께 열심히 준비중인 컨퍼런스가 열립니다. ^^ 많은 참여 부탁드립니다.


얼마 전에 JSON을 사용해서 AJAX 통신 API를 만드는 과정에서 삽질을 한 적이 있다. 기본만 제대로 살폈으면 쉽게 넘어갈 수 있는 일이었는데 나의 얼렁뚱땅 대충대충 ‘필요하면 그때그때 찾아서 쓰면 되지 뭐.’ 라는 안일함이 하루의 시간을 날려먹는 상황을 낳고 말았다. 방법은 정말 간단했다.

헤맸던 소스: Before Source

  • ● TestForm.java

    @Data
    @NoArgsConstructor
    @ToString
    public class TestForm {
      private String id;
      private String name;
      private List<TestTag> testTags;
    
      @Data
      @NoArgsConstructor
      @ToString
      public class TestTag {
          private String id;
          private String tag;
      }
    }
    
  • ● TestController.java

    @Controller
    public class TestController {
      private static final Logger logger = LoggerFactory.getLogger(TestController.class);
    
      @RequestMapping(value="/test", method=RequestMethod.GET)
      public void test(@RequestBody TestForm form, ModelMap map) {
          logger.debug("TestForm : {}", form);
      }
    }
    
  • ● Form JSON

      var form = {
          id: "123",
          name: "123",
          testTags: [{id: "1111", tag: "2222"}]
      };
    
      $.ajax({
          url: "http://localhost:8080/test",
          method: "get",
          type: "json",
          data: form,
          success: function(data) {
              console.log(data);
          }
      });
    

    여러가지 시도를 해봤지만, form의 데이터를 TestController의 test에서 제대로 받아들이지 못하는 문제로 골머리를 썩었다(지금 생각해보면 나의 무식함에 부끄럽지만).

해결 코드: After Source

  • ● TestForm.java

    @Data
    @NoArgsConstructor
    @ToString
    public class TestForm {
      private String id;
      private String name;
      private List<TestTag> testTags;
    
      @Data
      @NoArgsConstructor
      @ToString
      public static class TestTag {
          private String id;
          private String tag;
      }
    }
    
  • ● TestController.java

    @Controller
    public class TestController {
      private static final Logger logger = LoggerFactory.getLogger(TestController.class);
    
      @RequestMapping(value="/test", method=RequestMethod.POST)
      public void test(@RequestBody TestForm form, ModelMap map) {
          logger.debug("TestForm : {}", form);
      }
    }
    
  • ● Form JSON

      var form = {
          id: "123",
          name: "123",
          testTags: [{id: "1111", tag: "2222"}]
      };
    
      $.ajax({
          url: "http://localhost:8080/test",
          method: "post",
          type: "json",
          contentType: "application/json",
          data: JSON.stringify(form),
          success: function(data) {
              console.log(data);
          }
      });
    

Before Source와 After Source의 차이를 눈치챘는가? ㅡ_-)?
RequestMethod가 GET에서 POST로 변경되었다. 이에 대한 설명을 해본다. 토비의 스프링에 @RequestBody, @ResponseBody 를 살펴보기 바란다.

@RequestBody, @ResponseBody

최근 개발하고 있는 방식은 대부분이 프론트엔드와 백엔드를 분리하여 개발을 하고 있다. 프론트엔드의 AJAX요청은 대부분 JSON으로 되어 있고, 이에 맞춰 백엔드에서도 JSON 형태로 응답을 해주는 방식을 취하게 된다. 스프링에서는 이와 관련된 @MVC 관련 애노테이션과 설정을 통해 기능을 제공하고 있다.

  • ● @RequestBody

    이 애노테이션이 붙은 파라미터에는 HTTP 요청의 본문body 부분이 그대로 전달된다.
    AnnotationMethodHandlerAdapter에는 HttpMessageConverter 타입의 메시지 변환기message converter가 여러 개 등록되어 있다. @RequestBody가 붙은 파라미터가 있으면 HTTP 요청의 미디어 타입과 파라미터의 타입을 먼저 확인한다(servlet-context.xml 에서 <annotation-drvien> 태그 내에 선언하는 <message-converter> 에서 확인). 메시지 변환기 중에서 해당 미디어 타입과 파라미터 타입을 처리할 수 있다면, HTTP 요청의 본문 부분을 통째로 변환해서 지정된 메소드 파라미터로 전달해준다.

    내가 헤매던 부분이 바로 이부분이었다. ㅡ_-);;JSON 메시지 변환기에는 MappingJackson2HttpMessageConverter를 사용했다. @RequestBody 애노테이션은 요청에서 Body부분을 살펴 요청된 데이터를 추출하여 파라미터로 변환해주는데, ‘GET’ 메소드 요청의 경우에는 HTTP Body에 요청이 전달되는 것이 아니라, URL의 파라메터로 전달(ex: http://localhost:8080/test?id=123&name=123&testTag=…) 형식으로 전달되기 때문에 @RequestBody로 받으려고 해도 서로 다른 곳을 보며 데이터가 없다는 결과를 던질 수밖에 없다(이 부분도 로그에 대해서 상세하게 설정해서 살펴보면서 확인한 결과. 로그! 개발 중에 문제가 되는 요인들을 찾기 위해서 관심을 가지자).

  • ● @ResponseBody

    @ResponseBody는 @RequestBody와 비슷한 방식으로 동작한다. @ResponseBody가 메소드 레벨에서 부여되면 메소드가 리턴하는 오브젝트는 뷰를 통해 결과를 만들어내는 모델로 사용하는 대신, 메시지 컨버터를 통해 바로 HTTP 응답의 메시지 본문으로 변환된다.

    간단히 이야기 하자면, 요청한 형태에 맞춰서 메시지 변환기를 통해 결과값을 반환한다. ‘콩심은 데 콩나고 팥 심은데 팥난다.’ 랄까? ContentNegotiatingViewResolver 와는 동작방식이 좀 다르다. ContentNegotiatingViewResolver는 등록되어 있는 ViewResolver중에서 controller 메소드의 리턴값을 통해 등록된 ViewResolver 중에서 적합한 형태로 처리해서 반환하는 반면, @ResponseBody는 @RequestBody가 선택한 형식으로 결과값을 변환하여 반환한다고 보면 된다.

  • ● MessageConverter 메시지 변환기의 종류는 Spring API 문서를 참고하자.

정리

해당하는 애노테이션들이 어떻게 동작하는지 내가 했던 인터넷 설정들이 어떻게 반응하는지를 제대로 이해했다면, 별다른 삽질없이 조용히 넘어갈 수 있던 문제였는데, 쉬운 문제였다. 하아!!
요즘 들어서 부쩍 ‘기본을 탄탄히 갖춰야겠다.’라는 생각을 하게되는 일들이 많아지고 있다.

끊임없이 공부하고 공부하라!

  • ● 이와 관련된 내용들은 ‘[토비의 스프링]에서 [스프링 @MVC]’ 관련 내용을 상세하게 설명되어 있다.


Agenda

  • AngularJS Feature
  • Getting Started
  • Directives, Filters and Data binding
  • Views, Controllers and Scope
  • Modules, Routes and Factories

AgularJS Feature


Getting Started

  • Single Page Application(SPA)

    View1 -> View2 -> View3 -> View1

  • Challenge with SPAs

    DOM manipulation, History, Module loading, Routing, Caching, Object Modeling, Data binding, Ajax/Promises, View loading

  • AgularJS를 이용하면 하나의 프레임워크로 모든 기능을 사용할 수 있다.
  • AuglarJS is a full-featured SPA Framework.
    • ViewModel, Controllers, Views

Directives, Filters and Data binding

  • Directives

    • HTML new tricks
      <!DOCUTYPE html>
      <html ng-app> // Directive
      <head>
        <title></title>
      </head>
      <body>
        <div class="container">
            //ng-model is Directive
            // {{name}} is data binding expression
            Name: <input type="text" ng-model="name" /> {{name}}
        </div>
        <script src=""></script>
      </body>
      <html>
      
    • 참고 링크

    • ng-repeat: data-ng-app=”” -> data-ng-init=”names=[]” data-ng-

        <li data-ng-repeat="personName in names">{{personName}}</li>
      
  • Using Filters
    <li data-ng-repeat="cust in customers | filter:nameText | orderBy:'name'">{{cust.name}}-{{cust.city}}</li>
    

Views, Controllers and Scope

[View] <— $scope —> [Controller]
$scope is the “glue” (ViewModel)

  • Createing a View and Controller
    {{name}}
    function SimpleController($scope) {
      // $scope Dynamic inject
      $scope.customers=[{name:"", city:""}]
    }
    

Modules, Routes and Factories

  • Module -> Config -> Routes (->View ->Controller ->(*Factory): View <— $scope —> Controller)
  • Modules are Containers
    <html ng-app="moduleName">
    
  • Module

    • Config
      • Routes
    • Filter
    • Directive
    • Factory, Service, Provider, Value
    • Controller
      var demoApp = angular.module('demoApp', []);
      // What's the Array for?
      // Module that demoApp depends on ->[]
      var demoApp = angular.module('demoApp', ['helperModule']);
      
  • Creating a Controller in a module

      var demoApp = angular.module('demoApp', []);    //define a module
    
      demoApp.controller('SimpleController', function($scope) {    // define a controller
          $scope.customers = [
              //...
          ]
      });
    
  • the Role of Routes

    View1(/view1) -> View2(/view2) -> View3(/view3) -> View4(/view4) -> View1

      var demoApp = angular.module('demoApp', []);
    
      demoApp.config(function($routeProvider) {
          $routeProvider
              .when('/', // define Module Routes
                  {
                      contoller: 'SimpleController',
                      templateUrl: 'View1.html'
                  })
              .when('/partial2',
                  {
                      contoller: 'SimpleController',
                      templateUrl: 'View2.html'
                  })
              .otherwise({ redirectTo: '/'});
      });
    
  • Using Factories and Services

    • The Role of Factories
        var demoApp = angular.module('demoApp', [])
            .factory('simpleFactory', function() {
                var factory = {};
                var customers = {...};
                factory.getCustomers = function() {
                    return customers;
                };
                return factory;
            })
            .controller('SimpleController' function($scope, simpleFactory) {
                $scope.customers = simpleFactory.getCustomer();
            });
      
  • jQuery only used for Bootstrap

  • 참고 링크

참고링크


어제 권남님이 그래들gradle 튜토리얼을 진행해주실 때 프롬프트 옆에 깃의 브랜치명이 나타나는 모습을 보고 신기해서 찾아봤습니다. 그러다가 발견한 곳이
tag를 checkout 할 때 detached 라고 나오는 것이 보기 싫어서 찾아봤다.
http://oliverdavies.co.uk/blog/2013/04/27/display-git-branch-or-tag-names-your-bash-prompt
에 나와있는 일부 쉘parse_git_tag 을 추가해서 적용 후 확인 OK.

git branch 를 checkout 했을 경우:


git tag에 대해서 checkout 했을 경우:




프로젝트를 실행시키려고 했는데, 생성된 QueryDSL용 Q도메인(@Entity 애노테이션이 사용된 도메인 객체를 QueryDSL에서 변형가공)을 인식하지 못하는 문제가 발생했다. 이클립스에서는 별다른 문제없이 잘 되는 녀석이 인텔리제이에서는 Q도메인들을 찾지 못하는 문제를 뱉어낸 것이다. 그래서 인텔리제이에서 생성한 서버에서 사용하는 디렉토리를 확인했다. 서버에 배포된 클래스의 상태를 보니 Q도메인들이 빠져있어서 그렇다는 것을 확인했다.

8월 14, 2013 9:29:34 오전 org.apache.catalina.core.ApplicationContext log
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'companyServiceImpl': Injection of autowired dependencies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private net.slipp.rest.repository.CompanyRepository net.slipp.rest.service.impl.CompanyServiceImpl.companyRepository; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'companyRepositoryImpl' defined in file [/workspace/git-repository/rest-api-study/bin/WEB-INF/classes/net/slipp/rest/repository/CompanyRepositoryImpl.class]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [net.slipp.rest.repository.CompanyRepositoryImpl]: Constructor threw exception; nested exception is java.lang.IllegalArgumentException: Did not find a query class net.slipp.rest.domain.QCompany for domain class net.slipp.rest.domain.Company!
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:288)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1122)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:522)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:461)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:295)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:292)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:626)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:932)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:479)
    at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:389)
    at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:294)
    at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:112)
    at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4887)
    at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5381)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
    at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:901)
    at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:877)
    at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:633)
    at org.apache.catalina.startup.HostConfig.manageApp(HostConfig.java:1552)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.apache.tomcat.util.modeler.BaseModelMBean.invoke(BaseModelMBean.java:301)
    at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.invoke(DefaultMBeanServerInterceptor.java:819)
    at com.sun.jmx.mbeanserver.JmxMBeanServer.invoke(JmxMBeanServer.java:801)
    at org.apache.catalina.mbeans.MBeanFactory.createStandardContext(MBeanFactory.java:622)
    at org.apache.catalina.mbeans.MBeanFactory.createStandardContext(MBeanFactory.java:569)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.apache.tomcat.util.modeler.BaseModelMBean.invoke(BaseModelMBean.java:301)
    at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.invoke(DefaultMBeanServerInterceptor.java:819)
    at com.sun.jmx.mbeanserver.JmxMBeanServer.invoke(JmxMBeanServer.java:801)
    at javax.management.remote.rmi.RMIConnectionImpl.doOperation(RMIConnectionImpl.java:1487)
    at javax.management.remote.rmi.RMIConnectionImpl.access$300(RMIConnectionImpl.java:97)
    at javax.management.remote.rmi.RMIConnectionImpl$PrivilegedOperation.run(RMIConnectionImpl.java:1328)
    at javax.management.remote.rmi.RMIConnectionImpl.doPrivilegedOperation(RMIConnectionImpl.java:1420)
    at javax.management.remote.rmi.RMIConnectionImpl.invoke(RMIConnectionImpl.java:848)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:322)
    at sun.rmi.transport.Transport$1.run(Transport.java:177)
    at sun.rmi.transport.Transport$1.run(Transport.java:174)
    at java.security.AccessController.doPrivileged(Native Method)
    at sun.rmi.transport.Transport.serviceCall(Transport.java:173)
    at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:553)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:808)
    at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:667)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at java.lang.Thread.run(Thread.java:724)
Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: private net.slipp.rest.repository.CompanyRepository net.slipp.rest.service.impl.CompanyServiceImpl.companyRepository; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'companyRepositoryImpl' defined in file [/workspace/git-repository/rest-api-study/bin/WEB-INF/classes/net/slipp/rest/repository/CompanyRepositoryImpl.class]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [net.slipp.rest.repository.CompanyRepositoryImpl]: Constructor threw exception; nested exception is java.lang.IllegalArgumentException: Did not find a query class net.slipp.rest.domain.QCompany for domain class net.slipp.rest.domain.Company!
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:514)
    at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:87)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:285)
    ... 56 more
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'companyRepositoryImpl' defined in file [/workspace/git-repository/rest-api-study/bin/WEB-INF/classes/net/slipp/rest/repository/CompanyRepositoryImpl.class]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [net.slipp.rest.repository.CompanyRepositoryImpl]: Constructor threw exception; nested exception is java.lang.IllegalArgumentException: Did not find a query class net.slipp.rest.domain.QCompany for domain class net.slipp.rest.domain.Company!
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1013)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:959)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:490)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:461)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:295)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:292)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:285)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:910)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:853)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:768)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:486)
    ... 58 more
Caused by: org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [net.slipp.rest.repository.CompanyRepositoryImpl]: Constructor threw exception; nested exception is java.lang.IllegalArgumentException: Did not find a query class net.slipp.rest.domain.QCompany for domain class net.slipp.rest.domain.Company!
    at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:163)
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:87)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1006)
    ... 71 more
Caused by: java.lang.IllegalArgumentException: Did not find a query class net.slipp.rest.domain.QCompany for domain class net.slipp.rest.domain.Company!
    at org.springframework.data.querydsl.SimpleEntityPathResolver.createPath(SimpleEntityPathResolver.java:63)
    at net.slipp.rest.repository.querypredicate.AbstractJPAQueryPredicateExecutor.<init>(AbstractJPAQueryPredicateExecutor.java:47)
    at net.slipp.rest.repository.CompanyRepositoryImpl.<init>(CompanyRepositoryImpl.java:12)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:526)
    at org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:148)
    ... 73 more
Caused by: java.lang.ClassNotFoundException: net.slipp.rest.domain.QCompany
    at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1714)
    at org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1559)
    at org.springframework.util.ClassUtils.forName(ClassUtils.java:260)
    at org.springframework.data.querydsl.SimpleEntityPathResolver.createPath(SimpleEntityPathResolver.java:53)
    ... 80 more

8월 14, 2013 9:29:37 오전 org.apache.catalina.core.ApplicationContext log

인터넷을 통해 어떻게 처리해야할까 하고 잠시 검색한다.

그러다가 찾았다.

Unable to use Intellij with a generated sources folder :

http://stackoverflow.com/questions/5170620/unable-to-use-intellij-with-a-generated-sources-folder



 

 해결방법 

 

1. [File] -> [Project structure] -> [Module] -> [Sources] 탭으로 이동

2. (오른쪽 창에 있는) QueryDSL 소스디렉토리 선택

3. 마우스 우클릭

4. [Source] 선택
  Source로 선택된 디렉토리는 파란색으로 변경되고, 왼쪽에 등록된다. 

이걸 어제 찾아놓고 바로 확인 안하고 이제서야 확인을 했군요. Orz..

+ Recent posts