wintertreey 님의 블로그
@MVC DB연동2 JdbcDaoSupport 본문
JdbcDaoSupport를 이용해 db연동
Constructor Injection. why?
이건 (가상의) 필드주입 코드.
@Repository
public class DataDao extends JdbcDaoSupport {
@Autowired
private DataSource dataSource;
생성자 주입의 가장 큰 장점이 불변성을 보장한다는점이다. 생성자주입은 객체 생성 시점에 의존성을 주입하므로, "DataSource"와 같은 의존성을 final로 선언할 수 있다. 이로인해 객체의 상태를 보장할 수 있게 된다. 그 이외에도 테스트용이성, 명확한 의존성 명세등의 장점이 있다.
필드 주입의 경우 다음과 같은 문제점이 발생할 수 있다.
Testability: 필드 주입은 DataSource의 Mock 객체를 주입하는 것이 어렵다.
Encapsulation: dataSource와 같은 의존성이 public하거나 protected로 설정되지 않으면, 객체의 상태를 검사하거나 변경할 수 없다.
Immutability: dataSource의 의존성이 생성 후 변경될 수 있으므로, 객체의 상태를 불변으로 만들 수 없다.
이로인해 생성자주입은 Spring에서 권장하는 방법이고 주로 사용된다. 위와 같이 "DataSource"와 같은 중요한 의존성은 따라서 생성자 주입을 통해 설정하는 것이 좋다.
@PathVariable? vs @RequestParam
@PathVariable
URL 경로에서 데이터를 추출. URL 경로가 바뀌어야 함.
RESTful API의 일관성을 유지하는 데 유용. 변수명을 명시할 수 있어 URL 패턴이 명확하고 직관적.
@RequestParam
URL 쿼리 파라미터에서 데이터를 추출. URL 경로는 그대로 유지.
@Controller
public class ListController {
@Autowired
private MemberDao memberDao;
//@RequestParam 이용
@GetMapping("list")
public String listprocess(@RequestParam("jikwon_jik") String jikwonJik, Model model) {
List<MemberDto> list = memberDao.getMemberList(jikwonJik);
model.addAttribute("list", list);
return "list";
}
//@PathVariable 이용
@GetMapping("/list/{jikwon_jik}")
public String listprocess(@PathVariable("jikwon_jik") String jikwonJik, Model model) {
List<MemberDto> list = memberDao.getMemberList(jikwonJik);
model.addAttribute("list", list);
return "list";
}
}
@PathVariable을 사용하려면 폼의 action URL을 동적으로 설정해야 하므로 JavaScript를 사용하여 폼을 동적으로 생성해주야하는 등의 경로 변경을 주의해서 바꾸어주어야한다.
보다보니 문득 드는 궁금증.
/ 슬래시의 유무에 따른 경로설정
/가 있으면, 절대 경로. /가 없으면, 상대 경로.
- /list/{jikwon_jik}: 컨텍스트 루트부터 시작하는 절대 경로를 설정. 보다 명확하게 경로를 정의할 수 있다.
- list/{jikwon_jik}: 현재 컨트롤러의 기본 경로에 상대적인 경로를 설정. 컨트롤러의 경로 설정에 따라 달라질 수 있다.
그럼 자료를 읽어오고, CRUD 처리 과정을 하나씩 수행해보자.
전체자료 읽어오기
package pack.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import pack.model.MemberDao;
import pack.model.MemberDto;
@Controller
public class ListController {
@Autowired
private MemberDao memberDao;
@GetMapping("list")
public String listProcess(Model model) {
List<MemberDto> list = memberDao.getMemberList();
model.addAttribute("list", list);
return "list";
}
}
@Repository
public class MemberDao extends JdbcDaoSupport{
@Autowired
public MemberDao(DataSource dataSource) {
setDataSource(dataSource); //db연결정보 다 들어감.
}
//전체자료 읽기
public List<MemberDto> getMemberList(){
String sql = "select * from memberteb";
/*
List<MemberDto> list = getJdbcTemplate().query(sql, new RowMapper() {
@Override
public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
MemberDto member = new MemberDto();
member.setId(rs.getString("id"));
member.setName(rs.getString("name"));
member.setPasswd(rs.getString("passwd"));
member.setReg_date(rs.getString("reg_date"));
return member;
}
});
*/
//람다표현식
//인터페이스의 추상메소드가 한개여야만 가능!
List<MemberDto> list = getJdbcTemplate().query(sql, (ResultSet rs, int rowNum) -> {
MemberDto member = new MemberDto();
member.setId(rs.getString("id"));
member.setName(rs.getString("name"));
member.setPasswd(rs.getString("passwd"));
member.setReg_date(rs.getString("reg_date"));
return member;
});
return list;
}
주석처리 된 부분이 보통 하는 방식.
람다 표현식으로도 표현해보았다.
람다는 인터페이스의 추상메소드가 한개일때만 가능하다.
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h3>회원 정보(@MVC - db2: JdbcDaosupport)</h3>
<a href="insert">추가</a> 또는 <a th:href="@{/insert}">추가</a>
<table border="1">
<th:block th:if="${list.size > 0}">
<tr>
<td>아이디</td><td>회원명</td>
</tr>
<tr th:each="mem:${list}" >
<td th:text="${mem.id}">id</td>
<!--
<td th:text="${mem.name}">name</td>
-->
<td>
<a th:href="@{/detail(id=${mem.id})}" th:text="${mem.name}">name</a>
</td>
</tr>
</th:block>
</table>
</body>
</html>
자료 추가하기
추가링크가 두개이다. 오른쪽 추가링크(thymeleaf 형식)로 회원을 추가해보자.
@Controller
public class InsertController {
@Autowired
private MemberDao memberDao;
@GetMapping("insert") //추가를 눌렀을때 추가포맷이 뜨도록
public String form() {
return "insform";
}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
자료 추가 <p/>
<form th:action="@{/insert}" method="post">
id : <input type="text" name="id"><br>
pwd : <input type="text" name="passwd"><br>
name : <input type="text" name="name"><br>
<br>
<input type="submit" value="추가">
<input type="reset" value="초기화">
<input type="button" value="이전" onclick="history.back()">
</form>
</body>
</html>
@PostMapping("insert") //추가포맷의 내용을 추가해서 목록에 보이도록
public String submit(MemberBean bean) {
memberDao.insData(bean);
return "redirect:/list";// 추가 후 목록으로 이동
}
포워딩하면 추가된내용이 안보인다. 리다이랙트 해줘야함.
//자료 추가하기
public void insData(MemberBean bean) {
String sql = "insert into memberteb values(?,?,?,now())";
Object[] params = {bean.getId(), bean.getName(), bean.getPasswd()};
getJdbcTemplate().update(sql, params);
}
sql문은 싹다 MemberDao에 위치한다.
bean이든 string이든, object으로 받아서 param으로 넣어줘야한다.
밤밤밤이 추가되었다.
특정레코드읽기
@Controller
public class DetailController {
@Autowired
private MemberDao memberDao;
@GetMapping("detail")
public String detailProcess(@RequestParam("id") String id, Model model) {
MemberDto dto = memberDao.getMember(id);
model.addAttribute("member", dto);
return "detail";
}
}
//특정 레코드읽기
public MemberDto getMember(String id) {
String sql = "select * from memberteb where id=?";
MemberDto dto = (MemberDto)getJdbcTemplate().queryForObject(sql, new Object[] {id}, new RowMapper(){
@Override
public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
MemberDto dto = new MemberDto();
dto.setId(rs.getString("id"));
dto.setName(rs.getString("name"));
dto.setPasswd(rs.getString("passwd"));
dto.setReg_date(rs.getString("reg_date"));
return dto;
}
});
return dto;
}
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>template/detail.html</title>
</head>
<body>
<h3>🥕 회원 상세보기 🥕</h3>
아이디: [[${member.id}]]<br>
비밀번호: [[${member.passwd}]]<br>
회원명: [[${member.name}]]<br>
등록일: [[${member.reg_date}]]<br>
<br>
<a th:href="@{/list}">목록</a>
<a th:href="@{/update(id=${member.id})}">수정</a>
<a th:href="@{/delete(id=${member.id})}">삭제</a>
</body>
</html>
밤밤밤의 상세내용을 볼 수 있다.
수정하기
@Controller
public class UpdateController {
@Autowired
private MemberDao memberDao;
@GetMapping("update")
public String upform(@RequestParam("id") String id, Model model) {
MemberDto dto= memberDao.getMember(id);
model.addAttribute("member", dto);
return "upform";
}
//특정 레코드읽기
public MemberDto getMember(String id) {
String sql = "select * from memberteb where id=?";
MemberDto dto = (MemberDto)getJdbcTemplate().queryForObject(sql, new Object[] {id}, new RowMapper(){
@Override
public Object mapRow(ResultSet rs, int rowNum) throws SQLException {
MemberDto dto = new MemberDto();
dto.setId(rs.getString("id"));
dto.setName(rs.getString("name"));
dto.setPasswd(rs.getString("passwd"));
dto.setReg_date(rs.getString("reg_date"));
return dto;
}
});
return dto;
}
해당 id값에 맞는 데이터를 들고, 수정 포맷(upform)으로 간다.
<h3>🥕 회원정보 수정 🥕</h3>
<form th:action="@{/update}" method="post" th:object="${member}">
id : [[*{id}]] <input type="hidden" name="id" th:field="*{id}"><br>
passwd : <input type="text" th:field="*{passwd}"><br>
name : <input type="text" th:field="*{name}"><br>
<br>
<input type="submit" value="수정">
<input type="button" value="이전" onclick="history.back()">
</form>
th:object로 넘기면, th:field로 할때 *로 넘겨준다.
페이지 소스코드를 보면 자동으로 id, name을 만들어준다.
@PostMapping("update")
public String updateProcess(MemberBean bean, Model model) {
memberDao.upData(bean);
model.addAttribute("member", memberDao.getMember(bean.getId()));
return "detail"; //리다이렉팅한것. // 수정 후 목록보기로 이동
}
//수정
public void upData(MemberBean bean) {
String sql = "update memberteb set name=?, passwd=? where id=?";
getJdbcTemplate().update(sql, new Object[] {bean.getName(), bean.getPasswd(), bean.getId()});
}
삭제하기
@Controller
public class DeleteController {
@Autowired
private MemberDao memberDao;
@GetMapping("delete")
public String deleteProcess(@RequestParam("id") String id, Model model) {
memberDao.delData(id);
List<MemberDto> list = memberDao.getMemberList();
model.addAttribute("list",list);
return "list";
}
}
//삭제
public void delData(String id) {
String sql = "delete from memberteb where id=?";
getJdbcTemplate().update(sql, new Object[] {id});
}
https://www.inflearn.com/blogs/1284
절대주소 vs 상대주소 개념 정확히 이해하기 - 코딩웍스(Coding Works)님의 블로그 - 인프런 | 커뮤니
절대주소 vs 상대주소 개념 정확히 이해하기 - 안녕하세요. 코딩웍스입니다. 웹퍼블리싱을 시작하시는 분들이 혼란스러운 경우 중에 하나가 절대주소 vs 상대주소 개념입니다.실무에서 프로젝트
www.inflearn.com
https://dangdangee.tistory.com/entry/Spring-PathVariable-%EC%82%AC%EC%9A%A9%EB%B2%95
[Spring] @PathVariable 사용법
REST API에서 URL의 값을 처리하려면 어떻게 해야 할까? http://localhost:8080/mapping/userA userA라는 값을 url에서 가져오고 싶을 때 @PathVariable을 이용하면 쉽게 처리할 수 있다. @PathVariable 사용법 @GetMapping("/
dangdangee.tistory.com
'백엔드 > Spring' 카테고리의 다른 글
@MVC DB연동4 : Spring DATA JPA JpaRepository (0) | 2024.07.21 |
---|---|
@MVC DB연동4 : Spring DATA JPA CrudRepository (0) | 2024.07.21 |
Spring MVC. @RestController. @GetMapping @PostMapping @ReQuestMapping. (0) | 2024.07.16 |
Application yml. Thymeleaf 란? status. jar 배포. (1) | 2024.07.16 |
@MVC DB연동 1 (0) | 2024.07.16 |