Notice
Recent Posts
Recent Comments
Link
«   2024/10   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31
Tags
more
Archives
Today
Total
관리 메뉴

wintertreey 님의 블로그

@MVC DB연동2 JdbcDaoSupport 본문

Spring

@MVC DB연동2 JdbcDaoSupport

wintertreey 2024. 7. 21. 13:32

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>&nbsp;&nbsp;
<a th:href="@{/update(id=${member.id})}">수정</a>&nbsp;&nbsp;
<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