newlec SpringBoot
19. MyBatis 설정하는 방법
사용자 입출력을 위해 구현체가 직접 sql을 거치는게아니라 인터페이스를 통해 활용한다.
dao로 서비스를 구현한다.
자바 객체로만 데이터를 가져올 수있게 되는 것이다.
마이바티스가 dao의 반복적인 작업을 반복적인 소모성 코드를 줄여주는 역할을 한다.
mybatis설정 여러가지 설정이잇엇는데 많이 줄어들엇다.
db연결하려면 데이터소스 정보를 가져왓어야하는데 알아서 해준다.
ioc컨테이너에 담는것도 알아서 담아준다.
db계정만 설정하면된다.
멤버 객체를 구현할때 쿼리부분만 얹어주면 끝난다.
1.mysql 라이브러리 필요하다
2.스타터즈 필요하다.
20. Service와 Dao 구현체 준비하기
서비스라는 구현체와 DAO라는 인터페이스가 필요하다.
최소한의 기능이 있어야한다.
서비스객체에게 List를 달라고 한다.
NoticeService는 컨트롤러가 필요로하는 기능을 집합해둔 것이다.
notic객체를 리스트로 담아서 getList하자.
NotcieService객체를 만들고 여기의 getList를 메소드를 사용할 것이다.
각각 구현할 내용들을 만들어준다.
서비스는 또 직접 하는게 아니라 dao에서 하게 만들어야되서 Dao인터페이스를 또 생성해준다.
여기서 dao인터페이스가 제공받은것을 클래스로 구현해야하지만 이 구현하는 것을 마이바티스를 사용하면 직접 클래스를 만들필요가없다.
@Controller
@RequestMapping("/customer/notice/")
public class NoticeController {
@Autowired
private NoticeService service;
// list,detaili,edit,reg
@GetMapping("list")
public String list(Model model) {
List<Notice> list = service.getList();
//return "/customer/notice/list";
return "customer.notice.list";
}
@GetMapping("detail")
public String detail() {
Notice notice = service.get(1);
return "customer.notice.detail";
}
}public class NoticeServiceImp implements NoticeService{
private NoticeDao noticeDao;
@Override
public List<Notice> getList() {
List<Notice> list = noticeDao.getList();
return null;
}
@Override
public Notice get(int i) {
return null;
}
}public interface NoticeDao {
List<Notice> getList();
}21. Mapper 객체 만들기
마이바티스를 설정하고 구현해보자. 라이브러리를 추가해야한다.
pom.xml에서 설정해도되지만 스타터즈가 포함되어잇다.
프로젝트 우클릭 - spring - add staters mybatis와 mysql을 추가해주자.
알아서 업데이트 해준다. 이제 마이바티스의 본연의 업무인 NoticeDao를 구현하면되는데 그냥 매핑만 해주면된다.
@Mapper
public interface NoticeDao {
@Select("SELECT * FROM notice")
List<Notice> getList();
Notice get(int id);
}구문에따라 @Select @Insert등을 작성해주고 sql문을 넣어주면된다.
그리고 매핑이 되어있음을 알리기위해 @Mapper를 작성해주면된다.
밑에거도 꼭 해야하는 것은 아니고 구현하고싶은거만 구현하면된다.
이 db가 어디에잇고 사용자 게정번호 등이 무엇인지 알려줘야한다.
application.properties으로 가서 설정하면된다.
# mysql settings
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/db이름
spring.datasource.username=id
spring.datasource.password=비밀번호스프링 xml파일을 설정할때 datasource객체생성하여 DI햇던거랑 비슷하다.
spring MVC강의의 23번
국비에서 할때는 개인정보를 위해 아예 따로 빼고 application.properties에서 외부 설정을 가져왔다.
개인 공부에서는 그냥 로컬DB라 그냥 적었다.
이제 이것을 가져다쓰는 방법을 이해해야한다. IOC컨테이너와 DI를 알아야한다.
22. 스프링에서 객체 사용방법(dependency와 injection 그리고 IoC 컨테이너)
Dependency는 Product의 상대적인 이름이다. '의존성' '부품' B->C일때 C가 부품이다.
A->B->C하면 상대적인 관계가 되는것이다.
현실적으로 대부분의 프로그램은 Main함수가 없다면 다 부품이라고 할 수 있다.
class A {
private B b;
public A(){
}
public void setB(B b){
this.b = b;
}
}has a관계가 가장 많이 사용된다.
왜냐하면 보통 인터페이스를 이용해서 구현체를 사용하기 때문이다.
아직 구현체가 없어도 꽃으면되기때문에 영향이 없고 구현체가 달라져도 영향이 없어서 편하다.
누군가가 객체를 생성해야하는데 생성자에 꽃으면 이것을 constructor injection이라고 한다.
setter를 사용하면 setter injection인터페이스 기반하고 보통 객체꼽는 방법을 한다.
소스코드를 소스로 두지않고 설정으로 두는 경우가 많다.
xml지시서 작성 이걸 도와주는게 스프링이다.
스프링은 지시서를 가지고 IOC컨테이너(BEAN 컨테이너)에 담아준다.
이걸 DI하는 해주는 작업을 하고 컨테이너에서도 결합도 해준다.
이제 이 지시를 어노테이션으로 작성하면 쉽게 작성할 수 있다.
@Controller를 하면 ioc에 담아주고 injection해주는것이 @Autowired이다.
이관계를 만들어두면 인터페이스만 있고 구현체가 없는 상황이어도 상관이 없는 것이다.
23. Mapper 객체를 이용해서 공지목록 출력하기
NoitceController에서 사용한다.
customer의 NoitceController를 작성해보자.
컨트롤러에서는 Model에담에서 보내주기만 하면된다.
@Controller
@RequestMapping("/customer/notice/")
public class NoticeController {
@Autowired
private NoticeService service;
@GetMapping("list")
public String list(Model model) {
List<Notice> list = service.getList();
model.addAttribute("list", list);
return "customer.notice.list";
}
}NoticeService는 @Autowired어노테이션을 이용해서 알아서 주입되도록한다.
IOC컨테이너에 NoticeService 가 담겨잇다는 것을 전제로한다.
구현체는 NoticeServiceImp를 사용할 것인데 얘를 컨테이너에 담기위해 어노테이션을 달아줘야한다.
명백히 역할을 구분하기 위해 @Conponent보다는 @Service사용하는게 좋다.
@Service
public class NoticeServiceImp implements NoticeService{
@Autowired
private NoticeDao noticeDao;
@Override
public List<Notice> getList() {
List<Notice> list = noticeDao.getList();
return list;
}
}이녀석도 NoticeDao를 가져와야한다.
DAO를 구현해야하는데 @Mapper를 하면 마이바티스가 알아서 구현해줘서 알아서 IOC컨테이너에 담아주는 역할까지 해준다.
DAO에서 받아온 데이터를 담기 위해 DTO가 필요하다.
@Data
public class Notice {
private int id;
private String title;
private Date regdate;
private String content;
private int hit;
private boolean pub;
private int memberId;
}getter setter 필드 등등
이것을 컨트롤러가 받아오니 뷰단에서는 반복문으로 보여주면된다.
반복을 사용해야하니 태그 라이브러리 추가하면된다.
<%@ taglib prefix="c" uri="http://java.sun.com/jstl/core"%>
<c:forEach var="n" items="${list}">
<tr>
<td>${n.id}</td>
<td class="title indent text-align-left"><a href="detail">${n.title}</a></td>
<td>${n.memberId}</td>
<td>${n.regdate}</td>
<td>${n.hit}</td>
</tr>
</c:forEach>24. Notice 뷰 만들기
기존 Notice를 상속해서 만들자.
기존 List<Notice> 엿던것을 NoticeView로 변경해주자.
뷰페이지도 변경해준다. ${n.memberName}
다른 부모테이블의 컬럼이 필요하다면 뷰를 만들어서 해야한다.
25. MyBatis Column 매핑
db테이블 컬럼과 객체의 필드이름이 맞지 않을 경우 어떻게 해야하는지를 알아보자.
컬럼명이 언더바로 되잇을경우 이것을 담게되면 객체는 대소문자로 구분한다.
그럼 여기서 오류가 나는지 아닌지 알아야한다.
member_Name로 일단 변경해보자 . ->이러면 setter명과 다르기 때문에 담을 수 없다.
호환이 안된다. 이걸 해결하기 위해서 마이바티스 설정을 해주면된다.
@Mapper
public interface NoticeDao {
@Result(property = "memberName", column = "member_name")
@Select("select * from noticeniew")
List<NoticeView> getList();
Notice get(int id);
}마이바티스는 결과에 매핑하는 방법이 존재한다.
속성과 컬럼 이름을 일치하지 않는 것을 적어준다면 알아서 매핑해준다.
만약 두개이상이 안맞는다하면
복사해서 하나씩 담아주면된다. 여러개 작성하면된다.
@Result(property = "memberName", column = "member_name")
@Result(property = "regdate", column = "reg_date")
-> 예들을 하나로 묶는 방법도잇다.
@Results({
@Result(property = "memberName", column = "member_name"),
@Result(property = "regdate", column = "reg_date")
})
results안에 배열처럼 묶어주면된다.
그런데 사실 이렇게 억지스럽게 매핑을 할 필요가 없다.
db를 손댈수잇다면 객체에 맞게 이름을 고쳐주는게 낫다.
26. Mapper 에 Parameter 사용하기
서비스를 받을 때 아무 인자를 안주고 받을 일이 별로 없다.
NoitceController에서 인자를 주고 데이터를 받아온다고 생각해보자.
@GetMapping("list")
public String list(Model model) {
int page = 1;
String field = "title";
String query = "";
List<Notice> list = service.getList(page, field, query);
model.addAttribute("list", list);
return "customer.notice.list";
}서비스의 인자와 Dao의 인자와 같을 일이 별로없다.
Dao는 sql문을 대신하는 것이다.
이것을 구현하는것에 따라서 어떻게 할지 다르다.
서비스는 사용자가 요구하는 컨트롤러와 가깝다.
사용자가 1페이지를 달라고 하겟지만 쿼리에는 1페이지를 달라고 하는방법이 없다.
NoticeServiceImp 에서 페이지를 달라고 해보자.
@Override
public List<Notice> getList(int page, String field, String query) {
List<Notice> list = noticeDao.getList();
return list;
}10개씩끊어서 보겟다.
SELECT * FROM notice
ORDER BY regdate DESC
limit 0, 10;3이들어간거만 찾자하면 WHERE절을 붙여주면된다.
SELECT * FROM notice
WHERE title like '%3%'
ORDER BY regdate DESC
limit 0, 10;dao로가서 sql문을 바꿔주자.
+를 햇을때 sql이 붙어버리면 안되니 한칸씩 꼭 띄어쓰기 해줘야하는 것을 잊지말자.
@Select("SELECT * FROM notice "
+ "WHERE title like '%3%' "
+ "ORDER BY regdate DESC "
+ "limit 0, 10")
List<Notice> getList(int offset, int size, String field, String query);offset과 LIMIT WHERE절 like조건 4가지가 필요하다.
offset은
page 1->0 2->10 3->20 첫항이 0이고 공차가 10인 등차수열이다.
an=a1+(n-1)d ->0+(page-1)*10;
int size = 10;
int offset = 0+(page-1)*size;
10페이지씩 볼것이니까 size는 10이다.
@Override
public List<Notice> getList(int page, String field, String query) {
int size = 10;
int offset = 0+(page-1)*size; //page 1->0 2->10 3->20 첫항이 0이고 공차가 10인 등차수열
List<Notice> list = noticeDao.getList(offset, size, field, query);
return list;
}그럼 sql문에 이제 어떻게 이 값을 꽃을 것인가?
#{}으로 꽃으면된다. 그런데 #에 문자를 넣으면 '문자' 이런식으로 들어가게 되서 쿼리문이 작동을 안하게된다.
이를 해결하려면 ${}으로 작성하면 된다.
이러면 따옴표에 들어가는게 아니라 값을 받은대로 적어주게 된다.
JSP할때는 % + query + %이런식으로 햇엇는데 그럴필요가 없다.
@Mapper
public interface NoticeDao {
@Select("SELECT * FROM notice "
+ "WHERE title like '%${query}%' "
+ "ORDER BY regdate DESC "
+ "limit #{offset}, #{size}")
List<Notice> getList(int offset, int size, String field, String query);
} 결국 컨트롤러에서는 page 1 field title query에는""이 들어가게 되고 값이전달되고
서비스단은 dao에게 전달하게 dao스럽게 전달해주는 것이다.
27. XML을 이용한 매핑
어노테이션으로 sql을 매핑했엇는데 문제가 2가지 생긴다.
1.여기서 규모가 커지고 sql문이 복잡해지면 복잡해질수록 어지러워진다.
2.인터페이스가 특정 구현 기능과 강하게 밀접하는 것은 좋지않다.
마이바티스는 구현을 따로 해서 결합을 하지 않는다.
마이바티스는 사용함으로서 결합해버렷는데 이것은 좋지 않다.
3.구현해야할 목록이 눈에 잘띄지 않느다.
쿼리문이 너무 많이 차지해서 잘안보인다.
규모가 커지고 일반적으로 관리를 편하게 하려면
매핑을 어노테이션보다 xml을 하는게 좋다.
com.newlecture.web.dao.mabatis.mapper를 만들어주고
매핑하고자하는 Dao의 이름으로 NoticeDaoMapper.xml파일을 만들어주자.
어떤 인터페이스를 구현하고자 하는 것을 나타내줘야한다.
mybatis페이지 들어가서 시작하기 매핑된 SQL 구문 살펴보기 부분이 있어야한다.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.newlecture.web.dao.NoticeDao">
<select id="selectBlog" resultType="Blog">
select * from Blog where id = #{id}
</select>
</mapper>namespace에 뭐와 연결되어있는지를 인터페이스 풀네임을 작성해줘야한다.
select upadate insert delete등 구현하고자하려면
각각에 맞게 태그를 작성하면된다.
<select id=? resultType=?> id는 Dao의 함수명이다.
sql문은 ""이나 + 같은 것 없이 그냥 작성해주면된다. 내려쓰기도 자유롭다.
인터페이스는 인터페이스 대로 일을 하고 마이바티스에서 멀어지게 할 수잇다
그런데 이 실행후 결과집합을 어디에 담아야하나 어떤 객체에?
이것을 resultType에 풀네임으로담아주면된다.
이게 리스트인지 단일값인지는 작성해줄필요가 없다.
<select id="getList" resultType="com.newlecture.web.entity.Notice">
SELECT * FROM notice WHERE title like '%${query}%'
ORDER BY regdate DESC limit #{offset}, #{size}
</select>int insert(Notice notice);도 만들어보자.
리턴값이 정수값인데 이게 원하는게 아니라 입력값을 원한다.
Notice에 담을 것이기 때문에 인자로 들어오는 parameterType으로 받으면된다.
함수가 여러개가잇을때 사용할거만 구현해도 에러가 안난다.
xml로 정의햇을때 이 xml이 어디에잇는지 알려줘야한다.
application.properties에 추가해줘야한다.
mybatis.mapper-locations=classpath:com/newlecture/web/dao/mabatis/mapper/*.xml
Dao가 여러개라면 여러개의 xml을 만들것이니 *.xml로해주자.
28. XML Proposals 오류 문제
xml로 sql매핑을 햇다. xml을 다루며 Proposals기능이 꺼져있는 것을 발견햇다.
DOCTYPE dtd로되어잇다. 그런데 태그 목록이 안보인다.
이클립스 xml editer 다운받자
그런데 나는 이미 다운이 되어잇어서 보인다 이유는 알수없다.
29. NoticeService 인터페이스 정의하기
dao를 구현하기 전에 필요한 서비스가 무엇인지를 정의해보자.
ui를 보면서 필요한 것을 찾는 것이다.
NoticeService
-페이지를 처음으로 요청할때
1.List<Notice> getViewList(); (작성자이름을 나타내기 위해)
2.int getCount(); 1/n페이지 같은것
-검색을 요청할때
List<Notice> getViewList(String field, String query);
-페이지를 요청할때
1.List<Notice> getViewList(int page, String field, String query); 검색이있다면 검색에서 페이징
2.int getCount(String field, String query); 검색햇을 경우 1/n페이지 같은것
-일괄공개를 요청할때
int updatePubAll(int[] pubids, int[] closeids);
-일괄삭제를 요청할때
int deleteAll(int[] ids);
-자세한페이지 요청할때
Notice getView(id);
Notice getNext(id);
Notice getPrev(id);
-수정페이지를 요청할때
int update(Notice notice);
int delete(ind id);
int insert(Notice notice);
이것들이 우리가 공지사항을 관리할때 필요한 서비스들이다.
NoticeService에 우리가 구현할 서비스 목록을 넣어주자.
public interface NoticeService {
List<Notice> getList(int page, String field, String query);
Notice get(int i);
List<Notice> getViewList();
// -검색을 요청할때
List<Notice> getViewList(String field, String query);
// -페이지를 요청할때
List<Notice> getViewList(int page, String field, String query);
int getCount();
int getCount(String field, String query);
// -자세한페이지 요청할때
Notice getView(int id);
Notice getNext(int id);
Notice getPrev(int id);
// -일괄공개를 요청할때
int updatePubAll(int[] pubids, int[] closeids);
// -일괄삭제를 요청할때
int deleteAll(int[] ids);
// -수정페이지를 요청할때
int update(Notice notice);
int delete(int id);
int insert(Notice notice);
}30. NoticeDao 인터페이스 정의하기
NoticeService에 우리가 사용할 서비스들을 넣엇다.
이것을 구현하기 위해 dao를 구현해야한다.
NoticeService구현체를 구현하면서 dao가 어떤것을 구현해야하는지 정의해야한다.
public List<Notice> getViewList() {}의 경우 인자만 다른데 마지막것만 구현하면된다.
return에 마지막것을 호출하면서 인자값을 채워주면된다.
@Service
public class NoticeServiceImp implements NoticeService {
@Autowired
private NoticeDao noticeDao;
@Override
public Notice get(int i) {
return null;
}
@Override
public List<Notice> getViewList() {
return getViewList(1, "title", "");
}
@Override
public List<Notice> getViewList(String field, String query) {
return getViewList(1, field, query);
}
@Override
public List<Notice> getViewList(int page, String field, String query) {
int size = 10;
int offset = 0 + (page - 1) * size;// page 1->0 2->10 3->20 첫항이 0이고 공차가 10인 등차수열
List<Notice> list = noticeDao.getList(offset, size, field, query);
return list;
}
@Override
public int getCount() {
return getCount("title", "");
}
@Override
public int getCount(String field, String query) {
return noticeDao.getCount(field, query);
}
@Override
public Notice getView(int id) {
Notice notice = noticeDao.get(id);
return notice;
}
@Override
public Notice getNext(int id) {
return noticeDao.getNext(id);
}
@Override
public Notice getPrev(int id) {
return noticeDao.getPrev(id);
}
@Override
public int updatePubAll(int[] pubids, int[] closeids) {
return noticeDao.updatePubAll(pubids,closeids);
}
@Override
public int deleteAll(int[] ids) {
return noticeDao.deleteAll(ids);
}
@Override
public int update(Notice notice) {
return noticeDao.update(notice);
}
@Override
public int delete(int id) {
return noticeDao.delete(id);
}
@Override
public int insert(Notice notice) {
return noticeDao.insert(notice);
}
}@Mapper
public interface NoticeDao {
List<Notice> getViewList(int offset, int size, String field, String query);
Notice get(int id);
int insert(Notice notice);
int getCount(String field, String query);
Notice getNext(int id);
Notice getPrev(int id);
int updatePubAll(int[] pubids, int[] closeids);
int update(Notice notice);
int deleteAll(int[] ids);
int delete(int id);
} 이제 dao를 마이바티스 사용해서 구현하기만 하면된다.
'기초단계 > SPRING' 카테고리의 다른 글
| 2023.05.02 Spring 김영한 (0) | 2023.05.02 |
|---|---|
| 2023.04.28 Spring (0) | 2023.04.28 |
| 2023.04.24 Spring (0) | 2023.04.24 |
| 2023.04.22 Spring (0) | 2023.04.24 |
| 2023.04.20 Spring (0) | 2023.04.20 |