본문 바로가기

포트폴리오 개발일지

2024-06-04 게시판검색 1.3 및 오류발생

현재 문제점

서비스를 구현하던 중 뭔가 이상함을 깨달았다ㅠ

지금 NoteMapper 클래스의

List<NoteVO> selectSearchList(SeartDTO searchDTO)

메서드가 나중에 문제가 될것 같았다. 반환형이 DB에서 select 문을 실행한 결과인 List\인데
검색결과 리스트 반환은 가능하지만 사용자가 검색했던 검색조건과 검색어를 반환할수 없는 문제가 있다.

어제까지 단순히 반환형에 꽂혀 매퍼 클래스의 반환형이 문제가 될줄 알았는데, 알바하면서 생각해보니 아닌것 같았다. Mapper에서는 DB 에서 select 한 결과를 반환하는게 맞는것 같고 사용자의
검색 조건과 검색어를 view까지 다시 반환해주는 추가적인 과정이 필요한것 같았다.

 

해결 방법 생각해보기..

여러가지 방법을 생각해봤는데 내가 할수 있고 말이 된다 싶은건 크게 두가지였다.

  1. 사용자가 검색을 한 view 에서 검색조건/검색어 파라미터를 컨트롤러에서 검색결과 view 로 바로 넘겨주기
  2. 검색조건/검색어/mapper에서 select 한 List\ 를 한번에 반환할수 있는 클래스 만들기

구체적인 근거는 없고 2번 방향이 나을것 같다는 근거없는 예상은 되지만,
처음에는 1번으로 구현을 시작했다. 특별한 이유가 있는건 아니고 나는 초보이기에 둘 다 구현해보고 더 나은방식을 고르고, 보완하는 방향으로 구현할 것이기 때문이다.

1번 구현하기 + 오류....


1. 우선, 서비스와 컨트롤러를 각각 아래처럼 작성하고 실행하여 view가 제대로 작동하는지 확인하려고 했다.

코드 펼치기
  
@Service  
@Log4j2  
@RequiredArgsConstructor  
public class NoteServiceImpl implements NoteService {

    private final NoteMapper noteMapper;   
    private final ModelMapper modelMapper;
  
    @Override public List<NoteDTO>getSearchList(SearchDTO searchDTO) {

    log.info("노트 서비스 getSearchList 호출");
   
    List<NoteDTO>noteDTOList = noteMapper.selectSearchList(searchDTO).stream()   

                .map(vo -> modelMapper.map(vo, NoteDTO.class))   

                .collect(Collectors.toList()); 
  
    return noteDTOList;   

    }   

}  
   
@Controller   
@Log4j2   
@RequestMapping("/note")   
@RequiredArgsConstructor   
public class NoteController {
  
    private final NoteService noteService;
  
    @GetMapping("/list") public void list(Model model, SearchDTO searchDTO) {

        log.info("노트 컨트롤러 list(검색 테스트용) 호출");

        model.addAttribute("dtoList", noteService.getSearchList(searchDTO));  
    }

}


2.코드 작성후 우선 서비스 테스트를 했다.

코드 펼치기
  
@Log4j2    
@ExtendWith(SpringExtension.class)    
@ContextConfiguration(locations = "file:src/main/webapp/WEB-INF/root-context.xml")    
public class NoteServiceTests {
  
    @Autowired    
    private NoteService noteService;
  
      @Test    
    public void testgetSearchList(){

      noteService.getSearchList(SearchDTO.builder()
          .types(Arrays.asList("title","content"))
          .keyword("java")
          .build()    
      ).forEach(dto -> log.info(dto));  
  
    }  

}  
  
결과  
\> 16:17:26 DEBUG \[org.leeinwon.studylink.mapper.NoteMapper.selectSearchList\] ==>  Preparing: select \* from notes WHERE ( title like concat('%', ?, '%') OR content like concat('%', ?, '%') ) order by id asc  
16:17:26 DEBUG \[org.leeinwon.studylink.mapper.NoteMapper.selectSearchList\] ==> Parameters: java(String), java(String)  
16:17:26 TRACE \[org.leeinwon.studylink.mapper.NoteMapper.selectSearchList\] <==    Columns: id, title, content, createdate, updatedate  
16:17:26 TRACE \[org.leeinwon.studylink.mapper.NoteMapper.selectSearchList\] <==        Row: 1600, java, 1, 2024-05-31 21:56:33, null  
16:17:26 DEBUG \[org.leeinwon.studylink.mapper.NoteMapper.selectSearchList\] <==      Total: 1  
16:17:26  INFO \[org.leeinwon.studylink.service.NoteServiceTests\] NoteDTO(id=1600, title=java, content=1, createdate=2024-05-31T21:56:33, updatedate=null)  

결과도 문제 없어서 다음 순서로 톰캣으로 구동후 view도 정상적으로 불러 올수 있는지 확인해본다


3. view 확인하기 & 에러!!!!

내용 펼치기
  
# HTTP 상태 500 – 내부 서버 오류  
\*\*타입\*\* 예외 보고  
\*\*메시지\*\* Request processing failed; nested exception is org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.builder.BuilderException: The expression 'types' evaluated to a null value.  
\*\*설명\*\* 서버가, 해당 요청을 충족시키지 못하게 하는 예기치 않은 조건을 맞닥뜨렸습니다.  
\*\*예외\*\*  
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.builder.BuilderException: The expression 'types' evaluated to a null value.org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1014)  
org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898)  
javax.servlet.http.HttpServlet.service(HttpServlet.java:529)  
org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)  
javax.servlet.http.HttpServlet.service(HttpServlet.java:623)  
org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)  
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)  
org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)  
\*\*근본 원인 (root cause)\*\*  
org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.builder.BuilderException: The expression 'types' evaluated to a null value.  
org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:96)  
org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:441)  
co[http://m.sun.proxy.$Proxy16.selectList(Unknown](http://m.sun.proxy.$Proxy16.selectList\(Unknown) Source)  
org.mybatis.spring.SqlSessionTemplate.selectList(SqlSessionTemplate.java:224)  
org.apache.ibatis.binding.MapperMethod.executeForMany(MapperMethod.java:147)  


톰캣 구동 후 localhost:8080/note/list 로 이동하자마자 위 처럼 500번 오류가 생겼다. 근본원인을 보면

org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.builder.BuilderException: The expression 'types' evaluated to a null value.

mybatis에서 예외가 발생했고, types 표현식이 null 이라고 한다. 좀 당황했다. 나는 아무 검색조건 없이 /note/list 를 요청 했고 당연히 types 는 null이고 전체 리스트가 나와야 했는데 types 가 null 로 평가된다고 오류가 났다..

아마도 xml에서 null 체크 하는 부분이 잘못된것 같은데 우선 컨트롤러부터 내려가면서 다시 확인해보기로 했다.


예외처리는 다음 일지에서!