오늘은
오늘부터 백엔드의 스프링을 들어가기 위한 수업이 시작되었고
저는 따로 자바스크립트를 다시 공부를 하며
노드와 리액트를 위한 공부를 시작하였습니다
학원 수업
Servlet/Jsp -> Maven -> Spring Freamework
메이븐 프로젝트 - 상품관리(등록, 수정, 구매)
Market 프로젝트
Dynamic Web Project -> Maven Project로 변환
* maven에 필요한 dependency 가져오기
<dependencies>
<!-- https://mvnrepository.com/artifact/javax.servlet/jstl -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.mysql/mysql-connector-j -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>8.2.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.30</version>
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/com.servlets/cos -->
<dependency>
<groupId>com.servlets</groupId>
<artifactId>cos</artifactId>
<version>09May2002</version>
</dependency>
</dependencies>
<M(model)V(view)C(controller)패턴>
mvn 리포지터리
- 회면(view) - 템플릿언어 : jsp(jstl)
- DB연결(model) - mysql driver
- VO, DAO - 롬복(lombok)
** jsp **
- index.jsp (mian.jsp)
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>KHMarket</title>
</head>
<body>
<%-- <%@ include file="header.jsp" %> --%>
<jsp:include page="header.jsp"/>
<div class="container my-3">
<h1 class="text-center">웹 마켓에 오신 것을 환영합니다</h1>
<div class="text-center my-4">
<img src="resources/images/main.jpg" alt="집이미지" style="width:500px" class="rounded-lg">
</div>
</div>
<jsp:include page="footer.jsp"/>
<%-- <%@ include file="footer.jsp" %> --%>
</body>
</html>
- product/list.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<!DOCTYPE html>
<html>
<head>
'
<meta charset="UTF-8">
<title>상품 목록</title>
</head>
<body>
<jsp:include page="../header.jsp" />
<div class="container my-3">
<h2 class="text-center">상품 목록</h2>
<div class="row" align="center">
<c:if test="${empty products}">
<p>상품이 없습니다</p>
</c:if>
<c:if test="${not empty products}">
<c:forEach items="${products}" var="product">
<div class="col-4 my-5">
<c:if test="${not empty product.pimage}">
<img src="../upload/${product.pimage}" style="width: 300px; height:300px;">
</c:if>
<h3>${product.pname}</h3>
<p>${product.category}</p>
<p>${product.price}원</p>
<a href="/productinfo.do?pid=${product.pid}"
class="btn btn-secondary">상세정보 »</a>
</div>
</c:forEach>
</c:if>
</div>
</div>
<jsp:include page="../footer.jsp" />
</body>
</html>
- product/pinfo.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>상품정보</title>
</head>
<body>
<jsp:include page="../header.jsp" />
<div class="container my-3">
<h2>상품정보</h2>
<div class="row">
<div class="col-5">
<img src="../upload/${product.pimage}" alt="" style="width:100%">
</div>
<div class="col-7">
<h3>상품명 : ${product.pname}</h3>
<p>상품설명 : ${product.description}</p>
<p><b>상품코드</b> : <span class="badge bg-dark">${product.pid}</span></p>
<p><b>분류</b> : ${product.category}</p>
<p><b>재고수</b> : ${product.pstock}</p>
<p><b>상태</b> : ${product.condition}</p>
<p><b>가격</b> : ${product.price}</p>
<form action="/addcart.do?pid=${product.pid}" name="addform" method="post">
<!-- 상품 주문 버튼을 클릭하면 폼이 전송되어야 함 -->
<a href="#" onclick="addToCart()" class="btn btn-success">상품 주문</a>
<a href="/productlist.do" class="btn btn-secondary">상품 목록 »</a>
</form>
</div>
</div>
</div>
<jsp:include page="../footer.jsp" />
<script>
let addToCart = function(){
if(confirm("상품을 주문하시겠습니까?")){ // 확인, 취소
document.addform.submit();
}else {
document.addform.reset();
}
}
</script>
</body>
</html>
- product/pfrom.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>상품등록</title>
</head>
<body>
<jsp:include page="../header.jsp" />
<div class="container my-3">
<h2>상품 등록</h2>
<div class="row">
<form action="/insertproduct.do" method="post" enctype="multipart/form-data">
<div class="form-group row my-3">
<label class="col-2">상품 코드</label>
<div class="col-3">
<p>상품코드 <input type="text" name="pid" class="form-control"></p>
</div>
</div>
<div class="form-group row my-3">
<label class="col-2">상품명</label>
<div class="col-3">
<p>상품명 <input type="text" name="pname" class="form-control"></p>
</div>
</div>
<div class="form-group row my-3">
<label class="col-2">가격</label>
<div class="col-3">
<p>가격 <input type="text" name="price" class="form-control"></p>
</div>
</div>
<div class="form-group row my-3">
<label class="col-2">상품 설명</label>
<div class="col-4">
<p>상품설명 <textarea rows="3" cols="40" name="description" class="form-control"></textarea></p>
</div>
</div>
<div class="form-group row my-3">
<label class="col-2">카테고리</label>
<div class="col-3">
<p>카테고리 <input type="text" name="category" class="form-control"></p>
</div>
</div>
<div class="form-group row my-3">
<label class="col-2">재고 수</label>
<div class="col-3">
<p>재고 수 <input type="text" name="pstock" class="form-control"></p>
</div>
</div>
<div class="form-group row my-3">
<label class="col-2">상태</label>
<div class="col-3">
<p>
<label><input type="radio" name="condition" value="New" checked>신상품</label>
<label><input type="radio" name="condition" value="Old">중고품</label>
</p>
</div>
</div>
<div class="form-group row my-3">
<label class="col-2">상품 이미지</label>
<div class="col-3">
<p>상품 이미지 <input type="file" name="pimage" class="form-control"></p>
</div>
</div>
<div class="form-group row my-3">
<div class="col-3">
<p><input type="submit" value="등록" class="btn btn-success"></p>
</div>
</div>
</form>
</div>
</div>
<jsp:include page="../footer.jsp" />
</body>
</html>
** java **
- controller/MainController(servlet)
package controller;
import java.io.IOException;
import java.util.Enumeration;
import java.util.List;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.oreilly.servlet.MultipartRequest;
import com.oreilly.servlet.multipart.DefaultFileRenamePolicy;
import model.Product;
import model.ProductDAO;
@WebServlet("*.do")
public class MainController extends HttpServlet {
private static final long serialVersionUID = 1L;
// 필드
ProductDAO pdao;
public MainController() {
pdao = new ProductDAO();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
doPost(request, response);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 한글 인코딩
request.setCharacterEncoding("utf-8");
// command 패턴 경로 설정
String uri = request.getRequestURI();
String command = uri.substring(uri.lastIndexOf("/"));
String nextPage = "";
if(command.equals("/main.do")) {
nextPage = "/main.jsp";
}else if(command.equals("/productlist.do")) {
// 목록 보기 메서드 호출
List<Product> productlist = pdao.getProductList();
// 모델 생성하기
request.setAttribute("products", productlist);
// 페이지 이동
nextPage = "/product/list.jsp";
}else if(command.equals("/productform.do")) {
nextPage = "/product/pform.jsp";
}else if(command.equals("/insertproduct.do")) {
String realFolder ="C:\\jspworks\\Market\\src\\main\\webapp\\upload";
int maxSize = 10*1024*1024; //10MB
String encType = "utf-8"; //파일이름 한글 인코딩
DefaultFileRenamePolicy policy = new DefaultFileRenamePolicy();
//5가지 인자
MultipartRequest multi = new MultipartRequest(request, realFolder, maxSize, encType, policy);
// 입력폼의 데이터 받기
String pid = multi.getParameter("pid");
String pname = multi.getParameter("pname");
int price = Integer.parseInt(multi.getParameter("price"));
String description = multi.getParameter("description");
String category = multi.getParameter("category");
int pstock = Integer.parseInt(multi.getParameter("pstock"));
String condition = multi.getParameter("condition");
// file 파라미터
Enumeration<?> files = multi.getFileNames();
String pimage = "";
while(files.hasMoreElements()) { //파일이름이 있는 동안 반복
String userFilename = (String)files.nextElement();
//실제 저장될 이름
pimage = multi.getFilesystemName(userFilename);
}
// 상품 객체 1개 생성
Product product = new Product();
product.setPid(pid);
product.setPname(pname);
product.setPrice(price);
product.setDescription(description);
product.setCategory(category);
product.setPstock(pstock);
product.setCondition(condition);
product.setPimage(pimage);
// db에 등록할 메서드 호출
pdao.insertProduct(product);
// 경로로 설정해주어야 데이터가 들어감
nextPage = "/productlist.do";
}else if(command.equals("/productinfo.do")) {
String pid = request.getParameter("pid");
// 상세보기 메서드 호출
Product product = pdao.getProduct(pid);
// 모델 생성
request.setAttribute("product", product);
nextPage = "/product/pinfo.jsp";
}
if(command.equals("/insertproduct.do")) {
response.sendRedirect("/productlist.do");
}else {
// 페이지 이동(forward), 리다이렉트(redirect)
RequestDispatcher dispatch = request.getRequestDispatcher(nextPage);
dispatch.forward(request, response);
}
}
}
- common/JDBCTest, JDBCUtil
package common;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
// DB에 연결하고 종료하는 클래스
public class JDBCUtil {
static String driverClass = "com.mysql.cj.jdbc.Driver";
static String url = "jdbc:mysql://localhost:3306/jwebdb?serverTime=Asia/Seoul";
static String user = "jweb";
static String password = "pwjweb";
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
// DB 연결 메서드
public static Connection getConnection() {
try {
Class.forName(driverClass);
// 연결 됐을 때의 return
return DriverManager.getConnection(url, user, password);
} catch (Exception e) {
e.printStackTrace();
}
// 연결이 안됐을 때의 return
return null;
}
// DB 종료 메서드(추가, 수정, 삭제)
public static void close(Connection conn, PreparedStatement pstmt) {
if(pstmt != null) {
try {
pstmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
// DB 종료 메서드(검색)
public static void close(Connection conn, PreparedStatement pstmt, ResultSet rs) {
if(rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(pstmt != null) {
try {
pstmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if(conn != null) {
try {
conn.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
- model/Product, ProductDAO
package model;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import common.JDBCUtil;
public class ProductDAO {
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
// 목록 보기
public List<Product> getProductList(){
List<Product> productlist = new ArrayList<>();
try {
// db연결
conn = JDBCUtil.getConnection();
// sql처리
String sql = "select * from product";
pstmt = conn.prepareStatement(sql);
rs = pstmt.executeQuery();
while(rs.next()) {
Product p = new Product();
p.setPno(rs.getInt("p_no"));
p.setPid(rs.getString("p_id"));
p.setPname(rs.getString("p_name"));
p.setPrice(rs.getInt("p_price"));
p.setDescription(rs.getString("p_description"));
p.setCategory(rs.getString("p_category"));
p.setPstock(rs.getLong("p_stock"));
p.setCondition(rs.getString("p_condition"));
p.setPimage(rs.getString("p_image"));
p.setRegDate(rs.getTimestamp("regdate"));
p.setUpdateDate(rs.getTimestamp("updatedate"));
productlist.add(p); // 리스트에 객체 저장
}
} catch (SQLException e) {
e.printStackTrace();
} finally { // db종료
JDBCUtil.close(conn, pstmt, rs);
}
return productlist;
}
//상품 등록 메서드
public void insertProduct(Product p) {
try {
// db연결
conn = JDBCUtil.getConnection();
// sql처리
String sql = "insert into product(p_id, p_name, p_price, p_description, "
+ "p_category, p_stock, p_condition, p_image) "
+ "values (?, ?, ?, ?, ?, ?, ?, ? )";
pstmt = conn.prepareStatement(sql);
pstmt.setString(1, p.getPid());
pstmt.setString(2, p.getPname());
pstmt.setInt(3, p.getPrice());
pstmt.setString(4, p.getDescription());
pstmt.setString(5, p.getCategory());
pstmt.setLong(6, p.getPstock());
pstmt.setString(7, p.getCondition());
pstmt.setString(8, p.getPimage());
// sql 실행
pstmt.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
} finally { // db종료
JDBCUtil.close(conn, pstmt);
}
}
public Product getProduct(String pid) {
Product p = new Product();
try {
// db연결
conn = JDBCUtil.getConnection();
// sql처리
String sql = "select * from product where p_id=?";
pstmt = conn.prepareStatement(sql);
pstmt.setString(1, pid);
rs = pstmt.executeQuery();
if(rs.next()) {
p.setPno(rs.getInt("p_no"));
p.setPid(rs.getString("p_id"));
p.setPname(rs.getString("p_name"));
p.setPrice(rs.getInt("p_price"));
p.setDescription(rs.getString("p_description"));
p.setCategory(rs.getString("p_category"));
p.setPstock(rs.getLong("p_stock"));
p.setCondition(rs.getString("p_condition"));
p.setPimage(rs.getString("p_image"));
p.setRegDate(rs.getTimestamp("regdate"));
p.setUpdateDate(rs.getTimestamp("updatedate"));
}
} catch (SQLException e) {
e.printStackTrace();
} finally { // db종료
JDBCUtil.close(conn, pstmt, rs);
}
return p;
}
}
** db **
- table: product
use jwebdb;
create table product (
p_no int primary key auto_increment, -- 일련번호
p_id varchar(10) unique, -- 상품코드
p_name varchar(30) not null, -- 상품명
p_price int not null, -- 상품 가격
p_description text not null, -- 상품 설명
p_category varchar(30), -- 상품 분류
p_stock long, -- 재고수
p_condition varchar(20), -- 신상품, 중고품
p_image varchar(30), -- 상품 이미지
regdate datetime default now(), -- 등록일
upadatedate datetime -- 수정일
);
select * from product;
insert into product(p_id, p_name, p_price, p_description,
p_category, p_stock, p_condition, p_image)
values ('p1234', 'Galaxy21', '1500000', '저장 용량 64GB, 화면 크기 6.2인치',
'smart phone', '10000', '신상품', 'p1234.png');
** resources **
- css, js, images, sql
*js
let addToCart = function(){
if(confirm("상품을 주문하시겠습니까?")){ // 확인, 취소
document.addform.submit();
}else {
document.addform.reset();
}
}
* css, js
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>
JavaScript 공부
<<콜백 탈출>>
콜백 지옥 = 연속되는 비동기 함수들을 처리할 때
비동기 처리의 결과값을 사용하기 위해서 콜백이 깊어지는 현상
<promise 객체>
= javaScript의 비동기를 돕는 객체
=> 비동기처리의 결과값을 핸들링할 수 있는 코드를 비동기 함수로부터 분리할 수 있다
* 비동기 작업이 가질 수 있는 3가지 상태
1. Pending(대기 상태) = 비동기가 진행중이거나
시작할 수도 없는 문제가 있는 상태
2. resolve 해결 -> Fulfilled(성공) = 이행, 성공 상태
의도한대로 비동기 작업이 정상적으로 완료된 상태
3. reject 거부 -> Rejected(실패) = 거부, 실패 상태
비동기 작업이 모종의 이유로 실패했음을 의미
* promise 객체와 내장 함수 .then(), .catch()
function isPositive(number, resolve, reject) {
setTimeout(()=>{
// 전달받은 number가 숫자형 타입이 아니라면 비동기 처리 -> 실패
// 전달받은 number가 숫자형 타입이 맞다면 비동기 처리 ->성공
if(typeof number == 'number'){
// 성공 -> resolve
resolve(number >= 0 ? "양수" : "음수");
}else {
// 실패 -> reject
reject("주어진 값이 숫자형 값이 아닙니다");
}
},2000) // 2s
} // 2초 뒤에 콜백함수를 실행 전달받은 인자를 판단해줌
// 함수 호출
// isPositive(
// [],
// (res)=>{
// console.log("성공적으로 수행됨 : ", res);
// },
// (err)=>{
// console.log("실패 하였음 : ", err);
// });
// function isPositiveP(){
// const executor = ()=>{setTimeout(()=>{if(''){}else{}},2000)}
// }
function isPositiveP(number) {
// 비동기 작업을 실질적으로 실행시켜 주는 함수 executor 생성
const executor = (resolve,reject) => { // 실행자
setTimeout(()=>{
if(typeof number == 'number'){
// 성공 -> resolve
console.log(number);
resolve(number >= 0 ? "양수" : "음수");
}else {
// 실패 -> reject
reject("주어진 값이 숫자형 값이 아닙니다");
}
},2000);
};
// 비동기 작업 자체인 Promise를 저장할 상수 asyncTask 생성
// new 키워드를 사용 -> promise 객체 생성자로 비동기작업 실행자 함수를 넘겨줌
const asyncTask = new Promise(executor);
// executor를 바로 실행하게 된다
return asyncTask;
// isPositiveP의 반환값이 promise로 바뀌게 된다
// 어떤 함수가 promise를 반환한다는 것
// = 이 함수는 비동기작업을 하고 그 작업의 결과를
// promise 객체로 반환을 받아서 사용할 수 있는 함수라는 것
}
const res = isPositiveP(101);
// promise의 내장 함수 .then(), .catch()
// res.then(()=>{}).catch(()=>{});
res
.then((res)=>{ // resolve
console.long("작업 성공 : ", res);
})
.catch((err)=>{ // reject
console.log("작업 실패 : ", err);
});
// resolve(number >= 0 ? "양수" : "음수"); 에서 전달한 양수라는 값이
// console.long("작업 성공 : ", res); 콜백 함수에 들어와서 실행 됨
* promise 객체 사용
// function taskA(a,b,cb){
// setTimeout(()=>{
// const res = a+b;
// cb(res);
// }, 3000);
// }
// function taskB(a,cb) {
// setTimeout(()=>{
// const res = a * 2;
// cb(res);
// }, 1000);
// }
// function taskC(a,cb) {
// setTimeout(()=>{
// const res = a * -1;
// cb(res);
// }, 2000);
// }
// Callback_Hell
// taskA(3,4,(a_res)=>{
// console.log("tesk A : ", a_res);
// taskB(a_res,(b_res)=>{
// console.log("task_B : ", b_res);
// taskC(b_res,(c_res)=>{
// console.log("task_C : ", c_res);
// });
// });
// });
// Promise() 객체사용 => .then(), .catch() 사용 가능
function taskA(a,b,){
return new Promise((resolve, reject)=>{
setTimeout(()=>{
const res = a + b;
resolve(res);
; }, 3000);
});
}
function taskB(a) {
return new Promise((resolve, reject)=>{
setTimeout(()=>{
const res = a * 2;
resolve(res);
}, 1000);
});
}
function taskC(a) {
return new Promise((resolve, reject)=>{
setTimeout(()=>{
const res = a * -1;
resolve(res);
}, 2000);
});
}
// .then()의 틀린 사용방법
// taskA(5,1).then((a_res)=>{
// console.log("A Result : ", a_res);
// taskB(a_res).then((b_res)=>{
// console.log("B Result : ", b_res);
// taskC(b_res).then((c_res)=>{
// console.log("C Result : ", c_res);
// })
// })
// })
// .then() chaining
taskA(5, 1).then((a_res)=>{
console.log("A Result : ", a_res);
return taskB(a_res);
}).then((b_res)=>{
console.log("A Result : ", b_res);
return taskC(b_res);
}).then((c_res)=>{
console.log("A Result : ", c_res);
// 콜백 함수 연결~
})
// promise()객체 사용시 =>
// 비동기 처리를 호출하는 코드와
// 결과를 처리하는 코드르 분리할 수 있다
// = 가독성있고 깔끔한 비동기 처리를 도와준다
2023. 12. 20 (수)
프로그래머 도전기 91일차 (2) | 2023.12.28 |
---|---|
프로그래머 도전기 90일차 (4) | 2023.12.21 |
프로그래머 도전기 88일차 (2) | 2023.12.19 |
프로그래머 도전기 87일차 (0) | 2023.12.16 |
프로그래머 도전기 86일차 (0) | 2023.12.14 |