중요 정보 처리하기
보안 파일을 만들때 이름을 오히려 평범하게 하는 것이 좋다.
url에 구조/기능/기술/data가 노출되기에
보안은 정석이 있으면 안된다! 왜? 뚫릴 수 있다.
🛒 ProductDao.java 상품 데이터베이스 처리
데이터베이스에서 상품 목록을 가져오는 역할
package com.shop.cafe.dao; // 이 파일이 'com.shop.cafe.dao'라는 그룹(패키지)에 속해 있어
import java.sql.*;
import java.util.*;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import com.shop.cafe.dto.Product;
@Component // 이 클래스는 데이터베이스와 연결하는 역할을 해!
public class ProductDao {
// 데이터베이스 연결 정보 (설정 파일에서 값을 가져와서 사용해)
@Value("${spring.datasource.driver-class-name}")
private String DB_DRIVER; // 데이터베이스 드라이버 이름
@Value("${spring.datasource.url}")
private String DB_URL; // 데이터베이스 주소
@Value("${spring.datasource.username}")
private String DB_USER; // 데이터베이스 사용자 이름
@Value("${spring.datasource.password}")
private String DB_PW; // 데이터베이스 비밀번호
// 모든 상품 목록을 가져오는 기능이야
public List<Product> getAllProducts() throws Exception {
Class.forName(DB_DRIVER); // 데이터베이스 연결을 위한 드라이버를 로드해!
String sql = "SELECT * FROM product"; // 상품 정보를 가져오는 SQL 문장이야
try (
Connection con = DriverManager.getConnection(DB_URL, DB_USER, DB_PW); // 데이터베이스 연결
PreparedStatement stmt = con.prepareStatement(sql); // SQL 실행 준비
ResultSet rs = stmt.executeQuery(); // SQL 실행하고 결과를 가져와
) {
List<Product> list = new ArrayList<>(); // 상품 목록을 저장할 리스트야
// 데이터베이스에서 상품 정보를 하나씩 가져와서 리스트에 추가해
while (rs.next()) {
int prodcode = rs.getInt("prodcode"); // 상품 코드 가져오기
String prodname = rs.getString("prodname"); // 상품 이름 가져오기
String pimg = rs.getString("pimg"); // 상품 이미지 가져오기
int price = rs.getInt("price"); // 상품 가격 가져오기
// 가져온 정보를 Product 객체로 만들어 리스트에 추가해
list.add(new Product(prodcode, price, prodname, pimg));
}
return list; // 상품 목록을 사용자에게 돌려줘
}
}
}
🛒 회원 정보 저장 클래스
상품 정보를 저장
package com.shop.cafe.dto;
import java.util.Date;
public class Member {
private String email, pwd, nickname; // 이메일, 비밀번호, 닉네임 저장
private Date registDate; // 가입 날짜 저장
// 이메일 값을 가져오는 함수
public String getEmail() {
return email;
}
// 이메일 값을 설정하는 함수
public void setEmail(String email) {
this.email = email;
}
// 비밀번호 값을 가져오는 함수
public String getPwd() {
return pwd;
}
// 비밀번호 값을 설정하는 함수
public void setPwd(String pwd) {
this.pwd = pwd;
}
// 닉네임 값을 가져오는 함수
public String getNickname() {
return nickname;
}
// 닉네임 값을 설정하는 함수
public void setNickname(String nickname) {
this.nickname = nickname;
}
// 가입 날짜 값을 가져오는 함수
public Date getRegistDate() {
return registDate;
}
// 가입 날짜 값을 설정하는 함수
public void setRegistDate(Date registDate) {
this.registDate = registDate;
}
// 기본 생성자 (아무 정보 없이 객체를 만들 때 사용)
public Member() {
super();
}
// 모든 정보를 받아서 객체를 만드는 생성자
public Member(String email, String pwd, String nickname, Date registDate) {
super();
this.email = email;
this.pwd = pwd;
this.nickname = nickname;
this.registDate = registDate;
}
// 객체의 정보를 출력할 때 어떤 내용을 보여줄지 설정
@Override
public String toString() {
return "Member [email=" + email + ", pwd=" + pwd + ", nickname=" + nickname + ", registDate=" + registDate + "]";
}
}
🛒 회원 정보(로그인 & 회원가입)를 데이터베이스에서 가져오거나 저장하는 역할
public class MemberDao 에서Dao는 biz 즉, 메서드 중
이름 규칙: 변수 + setter + getter
모든 class를 f/w에서 제어하는건좋지않다..
package com.shop.cafe.dao; // 'com.shop.cafe.dao'라는 그룹(패키지)에 속함
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.Statement;
import java.sql.ResultSet;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Repository;
import com.shop.cafe.dto.Member;
@Repository // 데베 연결 역할
public class MemberDao {
// 데이터베이스 연결 정보 (설정 파일에서 값을 가져와서 사용)
@Value("${spring.datasource.driver-class-name}")
private String DB_DRIVER; // 데이터베이스 드라이버 이름
@Value("${spring.datasource.url}")
private String DB_URL; // 데이터베이스 주소
@Value("${spring.datasource.username}")
private String DB_USER; // 데이터베이스 사용자 이름
@Value("${spring.datasource.password}")
private String DB_PW; // 데이터베이스 비밀번호
// 사용자가 로그인할 때 실행되는 기능
public Member login(Member m) throws Exception {
Class.forName(DB_DRIVER); // 데이터베이스 연결을 위한 드라이버를 로드
// 사용자가 입력한 이메일과 비밀번호로 회원 정보를 찾는 SQL 문장
String sql = "select * from member where email='" + m.getEmail() + "' and pwd='" + m.getPwd() + "' ";
try (
Connection con = DriverManager.getConnection(DB_URL, DB_USER, DB_PW); // 데이터베이스 연결
Statement stmt = con.createStatement(); // SQL 실행 도구
ResultSet rs = stmt.executeQuery(sql); // SQL 실행하고 결과를 가져옴
) {
if (rs.next()) { // 만약 결과가 있다면 (로그인 성공)
String nickname = rs.getString("nickname"); // 닉네임 가져오기
m.setNickname(nickname); // 닉네임 저장
return m; // 로그인한 회원 정보 돌려주기
} else { // 로그인 실패
return null;
}
}
}
// 새로운 사용자를 추가하는 기능
public void insertMember(Member m) throws Exception {
Class.forName(DB_DRIVER); // 데이터베이스 연결을 위한 드라이버를 로드
// 새로운 회원 정보를 저장하는 SQL 문장
String sql = "insert into member(nickname, pwd, email) values(?,?,?)";
try (
Connection con = DriverManager.getConnection(DB_URL, DB_USER, DB_PW); // 데이터베이스 연결
PreparedStatement stmt = con.prepareStatement(sql); // SQL 실행 준비
) {
stmt.setString(1, m.getNickname()); // 첫 번째 ? 자리에 닉네임 넣기
stmt.setString(2, m.getPwd()); // 두 번째 ? 자리에 비밀번호 넣기
stmt.setString(3, m.getEmail()); // 세 번째 ? 자리에 이메일 넣기
int i = stmt.executeUpdate(); // SQL 실행 (회원 정보 저장)
System.out.println(i + "행이 insert되었습니다."); // 몇 개의 데이터가 저장되었는지 출력
}
}
}
Statement란? SQL 실행 도구
=> SELECT, INSERT, UPDATE, DELETE 같은 명령어 실행 가능
Statement stmt = con.createStatement();
데베와 연결된 con 객체를 이용해 Statment 객체를 만든다는 의미
executeQuery()란?
SQL을 실행하고 결과를 가져오는 역할 => 데베에서 정보를 가져오는용도
rs.next()란?
ResultSet(조회 결과)의 다음 행(row)로 이동하는 역할
데이터 o → true 반환
데이터 x → false 반환
🧐 Nickname앞에 set이 붙는 이유?
m.setNickname(nickname); // 닉네임 저장
객체의 속성(변수)에 값을 설정하는 함수
nickname 값을 m객체에 저장하는 역할
setNickname()과 getNickname()의 차이점
객체의 속성(변수)에 직접 접근하는 걸 막기 위해 getter(값을 가져오는 함수)와 setter(값을 설정하는 함수)를 사용
🛒 상품 서비스
상품 정보를 가져오는 비즈니스 로직을 처리하는 서비스
package com.shop.cafe.service; // 파일이 'com.shop.cafe.service'라는 그룹(패키지)에 속함
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.shop.cafe.dao.ProductDao;
import com.shop.cafe.dto.Product;
@Service // 이 클래스는 서비스(로직 처리) 역할
public class ProductService {
@Autowired // ProductDao를 자동으로 연결해 (데이터베이스에서 상품 정보를 가져오는 역할)
ProductDao productDao;
// 모든 상품 목록을 가져오는 기능
public List<Product> getAllProducts() throws Exception {
return productDao.getAllProducts(); // 상품 정보를 데이터베이스에서 가져와서 돌려줌
}
}
🧐 @Autowired를 쓰면 왜 변수를 두 번선언하는 것처럼 보일까?
변수를 두번 선언하는게 아니라, @Autowired가 자동으로 객체를 연결하는 것
@Autowired는 spring이 자동으로 객체를 연결해주는 기능
@Autowired 없이 직접 객체를 만들려면?
public class ProductService {
ProductDao productDao = new ProductDao(); // 직접 객체 생성, new 키워드로 객체 만들기
}
throw Exception이란?
"이 메서드에서 예외(오류)가 발생할 수 있다는걸" 미리 알려주는 것
→ 예외가 발생하면 이 메서드를 호출한 곳에서 처리해야한다.
<해결방안>
1. try-catch로 직접 만들기
2. throws를 사용해 호출한 곳에서 처리해 넘기기
// 상품 목록을 가져오는 메서드
public List<Product> getAllProducts() throws Exception {
return productDao.getAllProducts(); // 데이터베이스에서 상품 정보를 가져옴
}
🛒 회원 로그인 & 회원가입 요청을 처리하는 컨트롤러
package com.shop.cafe.controller; // 이 파일이 'com.shop.cafe.controller'라는 그룹(패키지)에 속함
import java.util.HashMap;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import com.shop.cafe.dto.Member;
import com.shop.cafe.service.MemberService;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpSession;
@RestController // 이 클래스는 웹에서 요청을 받을 수 있는 컨트롤러
@CrossOrigin("http://172.30.1.46:5500/") // 이 주소에서 오는 요청을 허용
public class MemberController {
@Autowired // 자동으로 MemberService를 연결 (의존성 주입)
MemberService memberService;
// 사용자가 로그인할 때 실행되는 기능
@PostMapping("login") // 'login'이라는 주소로 요청이 오면 실행
public Map<String, String> login(@RequestBody Member m, HttpServletRequest request) {
Map<String,String> responseData = new HashMap<>(); // 결과를 담을 그릇을 준비
try {
m = memberService.login(m); // 아이디와 비밀번호 확인
if (m != null) { // 로그인 성공!
HttpSession session = request.getSession(); // 사용자의 로그인 정보를 저장할 공간을 만들어줘
System.out.println(session.getId()); // 세션 ID 출력 (확인용)
session.setAttribute("member", m); // 로그인한 사용자 정보 저장
responseData.put("msg", "ok"); // 성공 메시지 저장
} else { // 로그인 실패
responseData.put("msg", "다시 로그인해주세요");
}
} catch (Exception e) { // 로그인 중 오류 발생
e.printStackTrace(); // 오류 내용을 출력해줘 (개발자가 확인할 수 있게)
responseData.put("msg", "다시 로그인해주세요");
}
return responseData; // 결과를 사용자에게 돌려줌
}
// 새로운 사용자를 추가하는 기능
@PostMapping("insertMember") // 'insertMember'라는 주소로 요청이 오면 실행
public Map<String, String> insertMember(@RequestBody Member m) {
Map<String,String> responseData = new HashMap<>(); // 결과를 담을 그릇을 준비해
try {
memberService.insertMember(m); // 새로운 회원 정보를 저장
responseData.put("msg", "ok"); // 성공 메시지 저장
} catch (Exception e) { // 회원가입 중 오류 발생
e.printStackTrace(); // 오류 내용을 출력해줘 (개발자가 확인할 수 있게)
responseData.put("msg", e.getMessage()); // 오류 메시지 저장
}
return responseData; // 결과를 사용자에게 돌려줘
}
}
package com.shop.cafe; // 이 패키지는 'com.shop.cafe'라는 그룹 안에 있는 코드
import org.springframework.boot.SpringApplication; // 스프링 부트 애플리케이션을 실행하는 도구
import org.springframework.boot.autoconfigure.SpringBootApplication; // 스프링 부트 기본 설정을 자동으로 해주는 역할
import org.springframework.context.annotation.PropertySource; // 설정 파일을 불러올 때 사용하는 도구
// 이 클래스는 스프링 부트 애플리케이션의 시작점
@SpringBootApplication
@PropertySource("classpath:config/secu.properties") // 'config/secu.properties' 파일에서 설정
public class Project1Application {
// 프로그램이 시작되면 실행되는 부분
public static void main(String[] args) {
SpringApplication.run(Project1Application.class, args); // 스프링 부트를 실행하는 코드
}
}
회원 관련 API 컨트롤러
Map<String,String> responseData = new HashMap<>();
map인터페이스를 구현한 HashMap객체를 생성하는 코드
Map이란?
키와 값으로 데이터를 저장하는 자료구조
HashMap이란?
HashMap은 Map의 구현체 중 하나, 빠르게 데이터를 저장하고 검색 가능
- 키를 사용해 누구보다 빠르게 남들과는 다르게 값을 찾을 수 있다.
- 순서 보장x
다시 코드 설명
1. Map<String,String>
Map<키 타입, 값 타입> → 키와 값의 자료형을 지정
string → string이므로 키도 문자열, 값도문자
그래서 try-catch문에서 responseData.put("msg", "ok"); → msg라는 키에 "ok" 값을 저장
2. new HashMap<> ();
HashMap<>(); → Map 인터페이스를 구현한 클래스
HashMap 객체를 생성해서 responseData 변수에 저장
put(키, 값) → 데이터를 추가
get(키) → 데이터를 가져옴
🛒 상품 관련 API 컨트롤러
controller 브라어저에서 제일 먼저 요청할때 받아주는 앱
package com.shop.cafe.controller; // 이 파일이 'com.shop.cafe.controller'라는 그룹(패키지)에 속해 있어
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import com.shop.cafe.dto.Product;
import com.shop.cafe.service.ProductService;
@RestController // 이 클래스는 웹에서 요청을 받을 수 있는 컨트롤
@CrossOrigin("http://172.30.1.46:5500/") // 이 주소에서 오는 요청을 허용
public class ProductController {
@Autowired // 자동으로 ProductService를 연결해줘 (의존성 주입)
ProductService productService;
// 모든 상품 목록을 가져오는 기능
@GetMapping("getAllProducts") // 'getAllProducts'라는 주소로 요청이 오면 실행
public List<Product> getAllProducts() {
try {
return productService.getAllProducts(); // 상품 목록을 가져와서 사용자에게 보내
} catch (Exception e) { // 만약 오류가 나면
e.printStackTrace(); // 오류 내용을 출력 (개발자가 확인할 수 있게)
return null; // 오류가 발생하면 아무것도 보내지 않아
}
}
}
2. front
사용자가 웹에서 상품 목록을 보거나, 회원가입/로그인 요청을 할 때 실행되는 JavaScript 코드
웹페이지가 열리면 서버에서 상품 목록을 가져와서 화면에 보여줌
// 웹페이지가 로드될 때 실행되는 코드
window.onload = async () => {
// 서버에서 모든 상품 목록을 가져온다.
let productList = await fetch('http://localhost:8080/getAllProducts', {
method: 'GET',
});
console.log(productList); // 응답 결과 출력 (텍스트 형태)
productList = await productList.json(); // JSON 형태로 변환
console.log(productList); // 변환된 JSON 데이터 출력 (상품 리스트)
let productListDiv = ``; // HTML에 추가할 상품 리스트를 저장할 변수
// 상품 리스트를 화면에 표시하는 코드
productList.forEach((item) => {
productListDiv += `<div class="card m-3" style="width: 10rem;">
<img src="img/${item.pimg}" class="card-img-top" alt="...">
<div class="card-body">
<b class="card-title">${item.prodname}</b>
<p class="card-text text-danger">${item.price}</p>
<a href="#" class="btn btn-outline-info">장바구니 담기</a>
</div>
</div>`;
});
// HTML 페이지의 특정 부분에 상품 리스트를 추가
document.getElementById('productListDiv').innerHTML = productListDiv;
};
// 회원가입 버튼 클릭 시 실행되는 코드
document.getElementById('signupBtn').addEventListener('click', async () => {
// 입력한 회원 정보를 가져와
const nickname = document.getElementById('nickname').value;
const email = document.getElementById('email').value;
const pwd = document.getElementById('pwd').value;
const data = { nickname, email, pwd }; // 데이터를 객체로 저장
// 서버에 회원가입 요청을 보냄
let response = await fetch('http://localhost:8080/insertMember', {
method: 'POST',
headers: {
'Content-Type': 'application/json', // JSON 형식으로 보낸다는 것을 알려줌
},
body: JSON.stringify(data), // 데이터를 JSON 문자열로 변환
});
response = await response.json(); // 서버 응답을 JSON 형태로 변환
console.log(response);
// 회원가입 성공하면 모달창 닫기
if (response.msg === 'ok') {
console.log('ok');
const modal = bootstrap.Modal.getInstance(
document.getElementById('signupModal')
);
modal.hide(); // 모달 닫기
document.getElementById('signupLi').remove(); // 회원가입 버튼 없애기
} else {
alert(response.msg); // 오류 메시지 출력
}
});
// 로그인 버튼 클릭 시 실행되는 코드
document.getElementById('loginBtn').addEventListener('click', async () => {
// 입력한 이메일과 비밀번호 가져오기
const email = document.getElementById('loginEmail').value;
const pwd = document.getElementById('loginPwd').value;
const data = { email, pwd };
// 서버에 로그인 요청 보내기
let response = await fetch('http://localhost:8080/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json', // JSON 형식으로 보낸다는 것을 알려줌
},
body: JSON.stringify(data), // 데이터를 JSON 문자열로 변환
});
response = await response.json(); // 서버 응답을 JSON 형태로 변환
console.log(response);
alert(response.msg); // 로그인 성공 또는 실패 메시지 출력
});
📌 전체 흐름
1️⃣ 사용자가 웹에서 상품 목록을 요청하면
→ ProductController가 ProductService를 호출
→ ProductService가 ProductDao를 호출
→ ProductDao가 데이터베이스에서 상품 정보를 가져옴
→ 가져온 데이터를 웹에 표시
2️⃣ 사용자가 회원가입하면
→ MemberController가 MemberService를 호출
→ MemberService가 MemberDao를 호출
→ MemberDao가 데이터베이스에 회원 정보를 저장함
→ 성공하면 ok 메시지를 응답
3️⃣ 사용자가 로그인하면
→ MemberController가 MemberService를 호출
→ MemberService가 MemberDao를 호출
→ MemberDao가 데이터베이스에서 회원 정보를 확인
→ 로그인 성공하면 ok, 실패하면 다시 로그인하세요 메시지를 응답
읽어보고 또 읽어보며 계속 이해하기
vscode랑 매일 실습한거랑 연동을 시켜놔 스프링에서 깃허브 연동시킬때 순간 당황하다가
수업이 끝난뒤 다시 파일을 만들어 연동을 시켰다.
스프링 스타터 파일을 처음 만들때는 익숙하지 않았는데 몇번 반복하니 간단하게 만들 수 있었다.
하지만 아직 자바언어는 익숙하지 않아..서.. 하나하나 의미를 다시 파악해야한다.. 사실 자바스크립트도 익숙하지 않아서..
어제는 수업 내용 다시 따라 해보느라 개인공부 못했다.. 좀 더 부지런하게 살아야겠
그나저나 마니또한테 말을 어케걸어야할지.. 말걸자마자 티날듯
수업실습할때마다 오류투성인 내 실습 파일.. 하나하나 해결하면 좀 기부니가 좋음
'💡 URECA > 🗒️ 스터디 노트' 카테고리의 다른 글
[URECA] Day 29 | Backend(4) 🛍️ (0) | 2025.03.07 |
---|---|
[URECA] Day28 | Backend(3) (0) | 2025.03.06 |
[URECA] Day 26 | SQL(2) (1) | 2025.03.04 |
[URECA] Day25 | SQL(1), JDBC (0) | 2025.02.28 |
[URECA] Day 24 | Git(2) (3) | 2025.02.27 |
중요 정보 처리하기
보안 파일을 만들때 이름을 오히려 평범하게 하는 것이 좋다.
url에 구조/기능/기술/data가 노출되기에
보안은 정석이 있으면 안된다! 왜? 뚫릴 수 있다.
🛒 ProductDao.java 상품 데이터베이스 처리
데이터베이스에서 상품 목록을 가져오는 역할
package com.shop.cafe.dao; // 이 파일이 'com.shop.cafe.dao'라는 그룹(패키지)에 속해 있어
import java.sql.*;
import java.util.*;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import com.shop.cafe.dto.Product;
@Component // 이 클래스는 데이터베이스와 연결하는 역할을 해!
public class ProductDao {
// 데이터베이스 연결 정보 (설정 파일에서 값을 가져와서 사용해)
@Value("${spring.datasource.driver-class-name}")
private String DB_DRIVER; // 데이터베이스 드라이버 이름
@Value("${spring.datasource.url}")
private String DB_URL; // 데이터베이스 주소
@Value("${spring.datasource.username}")
private String DB_USER; // 데이터베이스 사용자 이름
@Value("${spring.datasource.password}")
private String DB_PW; // 데이터베이스 비밀번호
// 모든 상품 목록을 가져오는 기능이야
public List<Product> getAllProducts() throws Exception {
Class.forName(DB_DRIVER); // 데이터베이스 연결을 위한 드라이버를 로드해!
String sql = "SELECT * FROM product"; // 상품 정보를 가져오는 SQL 문장이야
try (
Connection con = DriverManager.getConnection(DB_URL, DB_USER, DB_PW); // 데이터베이스 연결
PreparedStatement stmt = con.prepareStatement(sql); // SQL 실행 준비
ResultSet rs = stmt.executeQuery(); // SQL 실행하고 결과를 가져와
) {
List<Product> list = new ArrayList<>(); // 상품 목록을 저장할 리스트야
// 데이터베이스에서 상품 정보를 하나씩 가져와서 리스트에 추가해
while (rs.next()) {
int prodcode = rs.getInt("prodcode"); // 상품 코드 가져오기
String prodname = rs.getString("prodname"); // 상품 이름 가져오기
String pimg = rs.getString("pimg"); // 상품 이미지 가져오기
int price = rs.getInt("price"); // 상품 가격 가져오기
// 가져온 정보를 Product 객체로 만들어 리스트에 추가해
list.add(new Product(prodcode, price, prodname, pimg));
}
return list; // 상품 목록을 사용자에게 돌려줘
}
}
}
🛒 회원 정보 저장 클래스
상품 정보를 저장
package com.shop.cafe.dto;
import java.util.Date;
public class Member {
private String email, pwd, nickname; // 이메일, 비밀번호, 닉네임 저장
private Date registDate; // 가입 날짜 저장
// 이메일 값을 가져오는 함수
public String getEmail() {
return email;
}
// 이메일 값을 설정하는 함수
public void setEmail(String email) {
this.email = email;
}
// 비밀번호 값을 가져오는 함수
public String getPwd() {
return pwd;
}
// 비밀번호 값을 설정하는 함수
public void setPwd(String pwd) {
this.pwd = pwd;
}
// 닉네임 값을 가져오는 함수
public String getNickname() {
return nickname;
}
// 닉네임 값을 설정하는 함수
public void setNickname(String nickname) {
this.nickname = nickname;
}
// 가입 날짜 값을 가져오는 함수
public Date getRegistDate() {
return registDate;
}
// 가입 날짜 값을 설정하는 함수
public void setRegistDate(Date registDate) {
this.registDate = registDate;
}
// 기본 생성자 (아무 정보 없이 객체를 만들 때 사용)
public Member() {
super();
}
// 모든 정보를 받아서 객체를 만드는 생성자
public Member(String email, String pwd, String nickname, Date registDate) {
super();
this.email = email;
this.pwd = pwd;
this.nickname = nickname;
this.registDate = registDate;
}
// 객체의 정보를 출력할 때 어떤 내용을 보여줄지 설정
@Override
public String toString() {
return "Member [email=" + email + ", pwd=" + pwd + ", nickname=" + nickname + ", registDate=" + registDate + "]";
}
}
🛒 회원 정보(로그인 & 회원가입)를 데이터베이스에서 가져오거나 저장하는 역할
public class MemberDao 에서Dao는 biz 즉, 메서드 중
이름 규칙: 변수 + setter + getter
모든 class를 f/w에서 제어하는건좋지않다..
package com.shop.cafe.dao; // 'com.shop.cafe.dao'라는 그룹(패키지)에 속함
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.Statement;
import java.sql.ResultSet;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Repository;
import com.shop.cafe.dto.Member;
@Repository // 데베 연결 역할
public class MemberDao {
// 데이터베이스 연결 정보 (설정 파일에서 값을 가져와서 사용)
@Value("${spring.datasource.driver-class-name}")
private String DB_DRIVER; // 데이터베이스 드라이버 이름
@Value("${spring.datasource.url}")
private String DB_URL; // 데이터베이스 주소
@Value("${spring.datasource.username}")
private String DB_USER; // 데이터베이스 사용자 이름
@Value("${spring.datasource.password}")
private String DB_PW; // 데이터베이스 비밀번호
// 사용자가 로그인할 때 실행되는 기능
public Member login(Member m) throws Exception {
Class.forName(DB_DRIVER); // 데이터베이스 연결을 위한 드라이버를 로드
// 사용자가 입력한 이메일과 비밀번호로 회원 정보를 찾는 SQL 문장
String sql = "select * from member where email='" + m.getEmail() + "' and pwd='" + m.getPwd() + "' ";
try (
Connection con = DriverManager.getConnection(DB_URL, DB_USER, DB_PW); // 데이터베이스 연결
Statement stmt = con.createStatement(); // SQL 실행 도구
ResultSet rs = stmt.executeQuery(sql); // SQL 실행하고 결과를 가져옴
) {
if (rs.next()) { // 만약 결과가 있다면 (로그인 성공)
String nickname = rs.getString("nickname"); // 닉네임 가져오기
m.setNickname(nickname); // 닉네임 저장
return m; // 로그인한 회원 정보 돌려주기
} else { // 로그인 실패
return null;
}
}
}
// 새로운 사용자를 추가하는 기능
public void insertMember(Member m) throws Exception {
Class.forName(DB_DRIVER); // 데이터베이스 연결을 위한 드라이버를 로드
// 새로운 회원 정보를 저장하는 SQL 문장
String sql = "insert into member(nickname, pwd, email) values(?,?,?)";
try (
Connection con = DriverManager.getConnection(DB_URL, DB_USER, DB_PW); // 데이터베이스 연결
PreparedStatement stmt = con.prepareStatement(sql); // SQL 실행 준비
) {
stmt.setString(1, m.getNickname()); // 첫 번째 ? 자리에 닉네임 넣기
stmt.setString(2, m.getPwd()); // 두 번째 ? 자리에 비밀번호 넣기
stmt.setString(3, m.getEmail()); // 세 번째 ? 자리에 이메일 넣기
int i = stmt.executeUpdate(); // SQL 실행 (회원 정보 저장)
System.out.println(i + "행이 insert되었습니다."); // 몇 개의 데이터가 저장되었는지 출력
}
}
}
Statement란? SQL 실행 도구
=> SELECT, INSERT, UPDATE, DELETE 같은 명령어 실행 가능
Statement stmt = con.createStatement();
데베와 연결된 con 객체를 이용해 Statment 객체를 만든다는 의미
executeQuery()란?
SQL을 실행하고 결과를 가져오는 역할 => 데베에서 정보를 가져오는용도
rs.next()란?
ResultSet(조회 결과)의 다음 행(row)로 이동하는 역할
데이터 o → true 반환
데이터 x → false 반환
🧐 Nickname앞에 set이 붙는 이유?
m.setNickname(nickname); // 닉네임 저장
객체의 속성(변수)에 값을 설정하는 함수
nickname 값을 m객체에 저장하는 역할
setNickname()과 getNickname()의 차이점
객체의 속성(변수)에 직접 접근하는 걸 막기 위해 getter(값을 가져오는 함수)와 setter(값을 설정하는 함수)를 사용
🛒 상품 서비스
상품 정보를 가져오는 비즈니스 로직을 처리하는 서비스
package com.shop.cafe.service; // 파일이 'com.shop.cafe.service'라는 그룹(패키지)에 속함
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.shop.cafe.dao.ProductDao;
import com.shop.cafe.dto.Product;
@Service // 이 클래스는 서비스(로직 처리) 역할
public class ProductService {
@Autowired // ProductDao를 자동으로 연결해 (데이터베이스에서 상품 정보를 가져오는 역할)
ProductDao productDao;
// 모든 상품 목록을 가져오는 기능
public List<Product> getAllProducts() throws Exception {
return productDao.getAllProducts(); // 상품 정보를 데이터베이스에서 가져와서 돌려줌
}
}
🧐 @Autowired를 쓰면 왜 변수를 두 번선언하는 것처럼 보일까?
변수를 두번 선언하는게 아니라, @Autowired가 자동으로 객체를 연결하는 것
@Autowired는 spring이 자동으로 객체를 연결해주는 기능
@Autowired 없이 직접 객체를 만들려면?
public class ProductService {
ProductDao productDao = new ProductDao(); // 직접 객체 생성, new 키워드로 객체 만들기
}
throw Exception이란?
"이 메서드에서 예외(오류)가 발생할 수 있다는걸" 미리 알려주는 것
→ 예외가 발생하면 이 메서드를 호출한 곳에서 처리해야한다.
<해결방안>
1. try-catch로 직접 만들기
2. throws를 사용해 호출한 곳에서 처리해 넘기기
// 상품 목록을 가져오는 메서드
public List<Product> getAllProducts() throws Exception {
return productDao.getAllProducts(); // 데이터베이스에서 상품 정보를 가져옴
}
🛒 회원 로그인 & 회원가입 요청을 처리하는 컨트롤러
package com.shop.cafe.controller; // 이 파일이 'com.shop.cafe.controller'라는 그룹(패키지)에 속함
import java.util.HashMap;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import com.shop.cafe.dto.Member;
import com.shop.cafe.service.MemberService;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpSession;
@RestController // 이 클래스는 웹에서 요청을 받을 수 있는 컨트롤러
@CrossOrigin("http://172.30.1.46:5500/") // 이 주소에서 오는 요청을 허용
public class MemberController {
@Autowired // 자동으로 MemberService를 연결 (의존성 주입)
MemberService memberService;
// 사용자가 로그인할 때 실행되는 기능
@PostMapping("login") // 'login'이라는 주소로 요청이 오면 실행
public Map<String, String> login(@RequestBody Member m, HttpServletRequest request) {
Map<String,String> responseData = new HashMap<>(); // 결과를 담을 그릇을 준비
try {
m = memberService.login(m); // 아이디와 비밀번호 확인
if (m != null) { // 로그인 성공!
HttpSession session = request.getSession(); // 사용자의 로그인 정보를 저장할 공간을 만들어줘
System.out.println(session.getId()); // 세션 ID 출력 (확인용)
session.setAttribute("member", m); // 로그인한 사용자 정보 저장
responseData.put("msg", "ok"); // 성공 메시지 저장
} else { // 로그인 실패
responseData.put("msg", "다시 로그인해주세요");
}
} catch (Exception e) { // 로그인 중 오류 발생
e.printStackTrace(); // 오류 내용을 출력해줘 (개발자가 확인할 수 있게)
responseData.put("msg", "다시 로그인해주세요");
}
return responseData; // 결과를 사용자에게 돌려줌
}
// 새로운 사용자를 추가하는 기능
@PostMapping("insertMember") // 'insertMember'라는 주소로 요청이 오면 실행
public Map<String, String> insertMember(@RequestBody Member m) {
Map<String,String> responseData = new HashMap<>(); // 결과를 담을 그릇을 준비해
try {
memberService.insertMember(m); // 새로운 회원 정보를 저장
responseData.put("msg", "ok"); // 성공 메시지 저장
} catch (Exception e) { // 회원가입 중 오류 발생
e.printStackTrace(); // 오류 내용을 출력해줘 (개발자가 확인할 수 있게)
responseData.put("msg", e.getMessage()); // 오류 메시지 저장
}
return responseData; // 결과를 사용자에게 돌려줘
}
}
package com.shop.cafe; // 이 패키지는 'com.shop.cafe'라는 그룹 안에 있는 코드
import org.springframework.boot.SpringApplication; // 스프링 부트 애플리케이션을 실행하는 도구
import org.springframework.boot.autoconfigure.SpringBootApplication; // 스프링 부트 기본 설정을 자동으로 해주는 역할
import org.springframework.context.annotation.PropertySource; // 설정 파일을 불러올 때 사용하는 도구
// 이 클래스는 스프링 부트 애플리케이션의 시작점
@SpringBootApplication
@PropertySource("classpath:config/secu.properties") // 'config/secu.properties' 파일에서 설정
public class Project1Application {
// 프로그램이 시작되면 실행되는 부분
public static void main(String[] args) {
SpringApplication.run(Project1Application.class, args); // 스프링 부트를 실행하는 코드
}
}
회원 관련 API 컨트롤러
Map<String,String> responseData = new HashMap<>();
map인터페이스를 구현한 HashMap객체를 생성하는 코드
Map이란?
키와 값으로 데이터를 저장하는 자료구조
HashMap이란?
HashMap은 Map의 구현체 중 하나, 빠르게 데이터를 저장하고 검색 가능
- 키를 사용해 누구보다 빠르게 남들과는 다르게 값을 찾을 수 있다.
- 순서 보장x
다시 코드 설명
1. Map<String,String>
Map<키 타입, 값 타입> → 키와 값의 자료형을 지정
string → string이므로 키도 문자열, 값도문자
그래서 try-catch문에서 responseData.put("msg", "ok"); → msg라는 키에 "ok" 값을 저장
2. new HashMap<> ();
HashMap<>(); → Map 인터페이스를 구현한 클래스
HashMap 객체를 생성해서 responseData 변수에 저장
put(키, 값) → 데이터를 추가
get(키) → 데이터를 가져옴
🛒 상품 관련 API 컨트롤러
controller 브라어저에서 제일 먼저 요청할때 받아주는 앱
package com.shop.cafe.controller; // 이 파일이 'com.shop.cafe.controller'라는 그룹(패키지)에 속해 있어
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import com.shop.cafe.dto.Product;
import com.shop.cafe.service.ProductService;
@RestController // 이 클래스는 웹에서 요청을 받을 수 있는 컨트롤
@CrossOrigin("http://172.30.1.46:5500/") // 이 주소에서 오는 요청을 허용
public class ProductController {
@Autowired // 자동으로 ProductService를 연결해줘 (의존성 주입)
ProductService productService;
// 모든 상품 목록을 가져오는 기능
@GetMapping("getAllProducts") // 'getAllProducts'라는 주소로 요청이 오면 실행
public List<Product> getAllProducts() {
try {
return productService.getAllProducts(); // 상품 목록을 가져와서 사용자에게 보내
} catch (Exception e) { // 만약 오류가 나면
e.printStackTrace(); // 오류 내용을 출력 (개발자가 확인할 수 있게)
return null; // 오류가 발생하면 아무것도 보내지 않아
}
}
}
2. front
사용자가 웹에서 상품 목록을 보거나, 회원가입/로그인 요청을 할 때 실행되는 JavaScript 코드
웹페이지가 열리면 서버에서 상품 목록을 가져와서 화면에 보여줌
// 웹페이지가 로드될 때 실행되는 코드
window.onload = async () => {
// 서버에서 모든 상품 목록을 가져온다.
let productList = await fetch('http://localhost:8080/getAllProducts', {
method: 'GET',
});
console.log(productList); // 응답 결과 출력 (텍스트 형태)
productList = await productList.json(); // JSON 형태로 변환
console.log(productList); // 변환된 JSON 데이터 출력 (상품 리스트)
let productListDiv = ``; // HTML에 추가할 상품 리스트를 저장할 변수
// 상품 리스트를 화면에 표시하는 코드
productList.forEach((item) => {
productListDiv += `<div class="card m-3" style="width: 10rem;">
<img src="img/${item.pimg}" class="card-img-top" alt="...">
<div class="card-body">
<b class="card-title">${item.prodname}</b>
<p class="card-text text-danger">${item.price}</p>
<a href="#" class="btn btn-outline-info">장바구니 담기</a>
</div>
</div>`;
});
// HTML 페이지의 특정 부분에 상품 리스트를 추가
document.getElementById('productListDiv').innerHTML = productListDiv;
};
// 회원가입 버튼 클릭 시 실행되는 코드
document.getElementById('signupBtn').addEventListener('click', async () => {
// 입력한 회원 정보를 가져와
const nickname = document.getElementById('nickname').value;
const email = document.getElementById('email').value;
const pwd = document.getElementById('pwd').value;
const data = { nickname, email, pwd }; // 데이터를 객체로 저장
// 서버에 회원가입 요청을 보냄
let response = await fetch('http://localhost:8080/insertMember', {
method: 'POST',
headers: {
'Content-Type': 'application/json', // JSON 형식으로 보낸다는 것을 알려줌
},
body: JSON.stringify(data), // 데이터를 JSON 문자열로 변환
});
response = await response.json(); // 서버 응답을 JSON 형태로 변환
console.log(response);
// 회원가입 성공하면 모달창 닫기
if (response.msg === 'ok') {
console.log('ok');
const modal = bootstrap.Modal.getInstance(
document.getElementById('signupModal')
);
modal.hide(); // 모달 닫기
document.getElementById('signupLi').remove(); // 회원가입 버튼 없애기
} else {
alert(response.msg); // 오류 메시지 출력
}
});
// 로그인 버튼 클릭 시 실행되는 코드
document.getElementById('loginBtn').addEventListener('click', async () => {
// 입력한 이메일과 비밀번호 가져오기
const email = document.getElementById('loginEmail').value;
const pwd = document.getElementById('loginPwd').value;
const data = { email, pwd };
// 서버에 로그인 요청 보내기
let response = await fetch('http://localhost:8080/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json', // JSON 형식으로 보낸다는 것을 알려줌
},
body: JSON.stringify(data), // 데이터를 JSON 문자열로 변환
});
response = await response.json(); // 서버 응답을 JSON 형태로 변환
console.log(response);
alert(response.msg); // 로그인 성공 또는 실패 메시지 출력
});
📌 전체 흐름
1️⃣ 사용자가 웹에서 상품 목록을 요청하면
→ ProductController가 ProductService를 호출
→ ProductService가 ProductDao를 호출
→ ProductDao가 데이터베이스에서 상품 정보를 가져옴
→ 가져온 데이터를 웹에 표시
2️⃣ 사용자가 회원가입하면
→ MemberController가 MemberService를 호출
→ MemberService가 MemberDao를 호출
→ MemberDao가 데이터베이스에 회원 정보를 저장함
→ 성공하면 ok 메시지를 응답
3️⃣ 사용자가 로그인하면
→ MemberController가 MemberService를 호출
→ MemberService가 MemberDao를 호출
→ MemberDao가 데이터베이스에서 회원 정보를 확인
→ 로그인 성공하면 ok, 실패하면 다시 로그인하세요 메시지를 응답
읽어보고 또 읽어보며 계속 이해하기
vscode랑 매일 실습한거랑 연동을 시켜놔 스프링에서 깃허브 연동시킬때 순간 당황하다가
수업이 끝난뒤 다시 파일을 만들어 연동을 시켰다.
스프링 스타터 파일을 처음 만들때는 익숙하지 않았는데 몇번 반복하니 간단하게 만들 수 있었다.
하지만 아직 자바언어는 익숙하지 않아..서.. 하나하나 의미를 다시 파악해야한다.. 사실 자바스크립트도 익숙하지 않아서..
어제는 수업 내용 다시 따라 해보느라 개인공부 못했다.. 좀 더 부지런하게 살아야겠
그나저나 마니또한테 말을 어케걸어야할지.. 말걸자마자 티날듯
수업실습할때마다 오류투성인 내 실습 파일.. 하나하나 해결하면 좀 기부니가 좋음
'💡 URECA > 🗒️ 스터디 노트' 카테고리의 다른 글
[URECA] Day 29 | Backend(4) 🛍️ (0) | 2025.03.07 |
---|---|
[URECA] Day28 | Backend(3) (0) | 2025.03.06 |
[URECA] Day 26 | SQL(2) (1) | 2025.03.04 |
[URECA] Day25 | SQL(1), JDBC (0) | 2025.02.28 |
[URECA] Day 24 | Git(2) (3) | 2025.02.27 |