[23.12.04] 80차
<<진도>>
[Back-end] Spring Framework
/ Spring Legacy Project MVC 실습
/ JDBC(스프링 프레임워크)
/ mysql-connector-java를 이용한 java-mysql 연동
<<오늘의 팁>>
- Error 500번대는 server의 문제 / 400번대는 client의 문제
- Spring Framework는 @Autowired 가 없으면 자동 주입이 되지 않는다.(DI 시 생성자에 어노테이션 필수)- 참조형 Long의 초기값은 null !
- (복사한 프로젝트)계층 구조 마지막 이름(ver2)과 context(ver2copy) 가 같은 필요는 없다.
[ Spring Framework ]
< 과제 풀이 >
<%
String context = request.getContextPath();
System.out.println("[회원가입 view] context : " + context); //: /ver2
%>
<form action="<%=context %>/member/new" method="post">
<label for="name">이름 : </label>
<input type="text" name="name" id="name" placeholder="이름을 입력하세요...">
<input type= "submit" value="입력완료">
</form>
: POST방식 요청에 redirect:/ 시 GET방식 요청이된다.
[ PRG패턴 ]
Post Redirect Get
POST 요청이 오면 해당 요청을 수행한 후
Redirect를 시켜서
GET 요청으로 변환시켜는 다시 요청시키는 행위를 의미
@RequestMapping(value = "/new", method = RequestMethod.POST)
public String create(@RequestParam String name) {
Member member = new Member();
member.setName(name);
repository.save(member);
return "redirect:/";
}
Controller에 Repository 생성자 통해 의존성주입 후
/ MemberMemoryRepository - save()
@Repository
public class MemberMemoryRepository implements MemberRepository {
private static Map<Long, Member> store = new HashMap<Long, Member>();
private static Long sequence = 0L;
@Override
public Member save(Member member) {
member.setId(++sequence);
store.put(member.getId(), member);
return member;
}
/ MemberController - create()
@RequestMapping(value = "/new", method = RequestMethod.POST)
public String create(@ModelAttribute Member member) {
repository.save(member);
return "redirect:/";
}
/ MemberMemoryRepositsssory - findAll()
@Override
public List<Member> findAll() {
return new ArrayList<Member>(store.values());
}
/ MemberController.java - memberList
@RequestMapping(value = "/list", method = RequestMethod.GET)
public String memberList(Model model) {
List<Member> members = repository.findAll();
model.addAttribute("members", members);
return "member/memberList";
}
/ memberList.jsp
<%
List<Member> members = (List<Member>)request.getAttribute("members");
%>
<table>
<thead>
<tr>
<td>번호</td>
<td>이름</td>
</tr>
</thead>
<tbody>
<%for(Member member : members){%>
<tr>
<td><%=member.getId() %> </td>
<td><%=member.getName() %></td>
</tr>
<%} %>
</tbody>
</table>
** Lambda식은 자바 1.8ver 이상부터 지원, 프로젝트 properties
- 기본 lib를 사용하는 11버전으로 설정 후
- project Facets에서도 자바버전 설정
- pom.xml에서 프로젝트의 전체 java버전 코드수정을 해준다
: Spring Framework에서는 자바버전관리를 수동으로 해줘야함
(Spring Boot에서는 build.gradle에서 starter를 통해 jre/ java 버전관리를 자동으로 해준다)
- 또한 pom.xml에서 java버전과 spring버전을 맞춰줄 필요가있다.
(jdk 11은 최소 spring 5.1 이상버전 사용해야 한다)
POM.xml 코드 수정 시 Maven 버전도 모두 업데이트 된다.
[memberSearch]
/ MemberMemoryRepository
@Override
public Optional<Member> findById(Long id) {
return Optional.ofNullable(store.get(id));
}
@Override
public Optional<Member> findByName(String name) {
return store.values().stream()
.filter(n -> n.getName().equals(name))
.findAny();
}
/ MemberController
@RequestMapping(value = "/search", method = RequestMethod.GET)
public String memberSearch(@ModelAttribute Member member, Model model) {
Member searchMember = new Member();
if(member.getId() != null)
searchMember = repository.findById(member.getId()).get();
else if(!member.getName().isEmpty())
searchMember = repository.findByName(member.getName()).get();
model.addAttribute("member", searchMember);
return "member/search";
}
/ search.jsp
<!-- EL 활용 -->
<h1>검색 결과</h1>
<div>
<span>아이디 : </span>
<span>${ member.id }</span>
</div>
<div>
<span>이름 : </span>
<span>${ member.name }</span>
</div>
스프링 LEGACY 프로젝트 복사
1. 복사 후 컨텍스트를 바꿔주기
2. 프로젝트의 의존성을 관리하는 pom.xml
3. 변경 후 Tomcat server의 server.xml을 다시 보면
[JDBC]
Maven에 jdbc를 추가해줘야 한다.
< jdbc 설치관련 >
https://mvnrepository.com/tags/jdbc
MySQL과 Java를 연결해주는 connector
MySQL홈페이지에서 spring 프로젝트와 맞는 버전 재설치 필요 (ver 8.0.22)
다운그레이드 후 Connector 에 Maven 의존성 추가
https://mvnrepository.com/artifact/mysql/mysql-connector-java/8.0.22
Back 단에서 사용하는 것들은 root-context.xml에 추가
Spring Boot에서는 jdbc의 Datasource Bean이 자동으로 생성되지만
Spring Framework에서는 Bean을 모두 직접 만들어줘야 한다.
** Spring JDBC (아직사용하지는 않지만 DataSoure Bean을 사용하기위해 설치)
< DB 재설치 후 >
ver2 database - member table 생성
/ JdbcRepository를 만들고,
@Repository
public class MemberJdbcRepository implements MemberRepository{
private final DataSource dataSource;
@Autowired
public MemberJdbcRepository(DataSource dataSource) {
System.out.println("[MemberJdbcRepository] 실행됨");
this.dataSource = dataSource;
}
@Override
public Member save(Member member) {
return null;
}
@Override
public Optional<Member> findById(Long id) {
return null;
}
@Override
public Optional<Member> findByName(String name) {
return null;
}
@Override
public List<Member> findAll() {
return null;
}
}
** 이미 연결된 설정이된 mysql DB가 있음에도 서버가 재실행 될 때마다 mysql-connector-java.jar 파일이 실행되며,
중복해서 연결을 만드는 오류가 발생!
(=>구조적인 문제 : 따라서 프로젝트 내에서 계속 아닌 Tomcat에 옮겨 실행된느 위치를 지정해야 한다.)
/ JdbcRepository - save()
주석별로 기능 설명 참고
@Override
public Member save(Member member) {
String sql = "insert into member(name) values(?)"; // ?는 파라미터(? 1개 = 1번째)
Connection con = null;
PreparedStatement pstmt = null; // 동적 쿼리문에 필요
ResultSet rs = null;
// (DB)연결과 관련된 것은 모두 DataSource에 있다.
// getConnection() 예외처리 필요
try {
con = dataSource.getConnection();
pstmt = con.prepareStatement(sql, Statement.RETURN_GENERATED_KEYS);
// auto_increment(generated)인 'id' 준비
pstmt.setString(1, member.getName());
pstmt.executeUpdate(); // 값 변경이 아닌 DB에 요소 추가되는 Update 의미
rs = pstmt.getGeneratedKeys();
// return형 ResultSet에 관리되는 Row들 중 하나 객체반환
// (위에 코드에따라 실행되고, 마지막으로 자동 생성이된 Row하나 객체)
// java는 DBMS처럼 table(column)개념이 없기 때문에 모든 컬럼 정보도 함께 (하나의 객체 형태로)넘어온다.
if(rs.next()) { // 다음객체가 있다면
member.setId(rs.getLong(1)); // rs의 1번째 column(id)의 타입을 지정해서 값 세팅
}
} catch (Exception e) {
e.printStackTrace();
} finally {
//** 이렇게 지정해준 이후 다시 할당된 값을 역순으로 해제해줘야 한다.
try {
if(rs != null) rs.close();
if(pstmt != null) pstmt.close();
if(con != null) con.close();
}catch (Exception e2) { // 이 과정에서 또 예외처리 필요
e2.printStackTrace();
}
}
return member;
}
** Java App의 기준에서 DB와 데이터를 주고받는 작업은 I/O (Input / Output)가 발생하는데,
I/O가 발생하는 코드(ex) getConnection()등 )에는 예외가 발생하기 쉬워 무조건 예외처리가 되어있다.
cf) catch문의 .printStackTrace는 예외가 발생한곳에 스택트레이스가 출력되는 예외처리 메서드로 디버깅용,
실제 프로덕션 코드에서는 더 정교하고 적합한 예외처리가 필요하다.