1. mapper.java , mapper.xml 경로 잘 잡아줌
2. mapper.xml id와 mapper.java id 잘 잡아줌.
3. result type 문제. 다 바꿔 주고 테스트 해봤으나 아님.
위와 같은게 대부분이라서 인터넷에선 저런 부분들 해결만 나옴.
#다른 문제 :
Invalid bound statement (not found): com.example.dmf.weather.service.WeatherService.findAll
원인.
2022.11.30 : 한마디로 말하면 해결이 안됐다.
2022-12-01 : 해결됨
public class WeatherServiceImpl implements WeatherService
Service interface로 두고, serviceImpl로 구현해서 해당 부분을 mybatis로 받으니 에러가 나타남.
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
그래서 controller에서
@RestController
@RequestMapping(value = "/api/v1/app/")
public class WeatherApiController {
@Autowired
private WeatherMapper weatherMapper;
@Autowired
private WeatherService weatherService;
@Autowired
private WeatherServiceImpl weatherServiceImpl;
@RequestMapping(value= "findAll", method = RequestMethod.POST)
public ResponseEntity<?> findAll() throws Exception {
WeatherResponseDto weatherResponseDto = new WeatherResponseDto();
weatherResponseDto.setResultCode("S0001");
weatherResponseDto.setRes(weatherService.findAll());
return new ResponseEntity<>(weatherResponseDto, HttpStatus.OK);
}
}
으로 하면
Invalid bound statement (not found): com.example.dmf.weather.service.WeatherService.findAll 에러가 나타남.
하지만
@RestController
@RequestMapping(value = "/api/v1/app/")
public class WeatherApiController {
@Autowired
private WeatherMapper weatherMapper;
@Autowired
private WeatherService weatherService;
@Autowired
private WeatherServiceImpl weatherServiceImpl;
@RequestMapping(value= "findAll", method = RequestMethod.POST)
public ResponseEntity<?> findAll() throws Exception {
WeatherResponseDto weatherResponseDto = new WeatherResponseDto();
weatherResponseDto.setResultCode("S0001");
weatherResponseDto.setRes(weatherServiceImpl.findAll());
/* weatherResponseDto.setRes(weatherService.findAll()); */
return new ResponseEntity<>(weatherResponseDto, HttpStatus.OK);
}
}
로 하면 실행이 잘됨.
정확한 원인은 모르겠으나, 구글링을 뒤진 결과로는
dto , dao , mapper 등으로 mapper.xml을 통한 값을 들고 왔으면, 거기서 직접적인 호출이 이루어져야 한다고한다.
아직은 해결이 안됐으나, 추후에 해결이 된다면 다시 수정해서 글을 올리도록 함.
아니면 해결 방법을 아시는 분 있으시면 댓글 남겨주시면 감사히 세겨듣도록 하겠습니다.
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
# 해결
해결이라고 하면 위를 완벽히 해결 한건 아닌데, service로 인터페이스를 만들고 serviceImpl 구현을 해도 잘 불러와 지기 때문에. 해결이라고 하고 쓴다.
위와 같이 직접적인 호출이 이루어져야 한다고 했는데, 직접적인 호출로 이루어지게끔 다시 바꿈에도 불구하고
위 처럼 에러가 발생함. 그래서 아예 내가 셋팅을 잘못 했다고 생각하게됨.
1.
MyBatisConfig.java를 기존에
package com.example.dmf.config;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.sql.DataSource;
@Configuration
// 패키지명
@MapperScan(value = "com.example.dmf", sqlSessionFactoryRef = "SqlSessionFactory")
public class MyBatisConfig {
@Value("${spring.datasource.mapper-locations}")
String mPath;
@Bean(name = "dataSource")
@ConfigurationProperties(prefix = "spring.datasource")
public DataSource DataSource() {
return DataSourceBuilder.create().build();
}
@Bean(name = "SqlSessionFactory")
public SqlSessionFactory SqlSessionFactory(@Qualifier("dataSource") DataSource DataSource, ApplicationContext applicationContext) throws Exception {
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(DataSource);
sqlSessionFactoryBean.setMapperLocations(applicationContext.getResources(mPath));
sqlSessionFactoryBean.setConfigLocation(applicationContext.getResource("classpath:mybatis-config.xml"));
return sqlSessionFactoryBean.getObject();
}
@Bean(name = "SessionTemplate")
public SqlSessionTemplate SqlSessionTemplate(@Qualifier("SqlSessionFactory") SqlSessionFactory firstSqlSessionFactory) {
return new SqlSessionTemplate(firstSqlSessionFactory);
}
}
을 사용해주었다. 하지만 인터넷 찾아보니, 약간 오버 셋팅 같은 느낌이라서 아예 없애버렸다.(지우게됨)
2. build.gradle.kts
(코틀린 버전이라서 이거인데, 기존 build.gradle은 그냥 적혀있는거 대로 쓰고 아래 필요한org.mybatis.spring.boot만 쓰자)
implementation("org.mybatis.spring.boot:mybatis-spring-boot-starter:2.2.2") /* mybatis */
3. Mapper.xml
resources/mapper/BoardMapper.xml (*경로가 가장 중요)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.dmf.mapper.BoardMapper">
<select id="selectBoardList" resultType="com.example.dmf.board.dto.BoardDto">
<![CDATA[
SELECT
board_idx,
title,
hit_cnt
FROM
t_board
WHERE
delete_yn = 'N'
ORDER BY board_idx DESC
]]>
</select>
</mapper>
그 다음으로 중요한 것은 id => interface와 맞춰줘야함. namespace => 마찬가지로 인터페이스와 맞춰줘야함.
resultType은
-> select -> resultType -> 담길 그릇
-> insert -> parameterType -> String, int 등 ~ 형식이 들어올 것이다 라고 알려주는 것. 이다.
Dto로 받을거라서 위에처럼 지정. Dto로 받는 이유가 있다면, jsonData로 깔끔하게 값을 받게끔이 큰 이유인거 같음.
4. service (interface)
import com.example.dmf.board.dto.BoardDto;
import java.util.List;
public interface BoardService {
List<BoardDto> selectBoardList() throws Exception;
}
5. serviceImpl (구현)
import com.example.dmf.board.dto.BoardDto;
import com.example.dmf.mapper.BoardMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
@Service
public class BoardServiceImpl implements BoardService{
@Autowired
private BoardMapper boardMapper;
@Override
public List<BoardDto> selectBoardList() throws Exception {
return boardMapper.selectBoardList();
}
}
6. controller
import com.example.dmf.board.dto.BoardDto;
import com.example.dmf.board.service.BoardService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import java.util.List;
@Controller
public class BoardController {
@Autowired
private BoardService boardService;
@RequestMapping("/apple")
public ModelAndView openBoardList() throws Exception{
ModelAndView mv = new ModelAndView("thymeleaf/apple/boardList");
List<BoardDto> list = boardService.selectBoardList();
mv.addObject("list",list);
return mv;
}
}
7. application.yml
mybatis:
mapper-locations: classpath:mapper/*.xml
으로 해주니
성공됨.