a = np.array([-1,3, 2, 6])
b = np.array([3,6,1,2])
A = a.reshape([2,2])
print(A)
print(f"A.ndim:{A.ndim}") # 2차원
print(f"A.shape:{A.shape}") #2,2
B = np.reshape(b,[2,2])
print(B)
print(f"A+B\n:{A+B}")
print(f"A*B\n:{A*B}")
print(f"np.matmul:\n{np.matmul(A,B)}")
$ sudo apt update
$ sudo apt install mysql-client -y
$ mysql -h [엔드포인트 붙여넣기] -P 3306 -u myroot -p
password:
>mysql(작성)
// ctrl + Z (mysql나가기)
$ cd
$ git clone https://github.com/seoljinuk/shopping_02_yes_database.git
$ ls
ec2_homepage shopping_02_yes_database
$ cd sh*
$ ls
$ cd src
$ cd main
$ cd resources
$ sudo vi application.properties
// 편집
url = localhost만 지우고 엔드포인트 붙여넣기
username = "작성"
userpassword ="작성"
// 저장 esc ;
:wq
$ cd
$ cd sho*
$ ls (pom.xml 위치한 곳에서 mvn메이븐 작성)
$ mvn package (test-compile 실행)
❗오류시 아래 코드 작성
---------------------------------------
$ sudo apt install maven
$ sudo apt install openjdk-17-jdk -y
$ sudo apt install -y maven
$ export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64
$ mvn clean compile
내 PC 고급시스템 설정-> 환경변수 설정 -> jdk17-bin위치 설정 -> 시스템 변수 설정 -> 편집
---------------------------------------
(target 이동)
$ ls
$ cd target
-- port 9000으로 수정
$ sudo iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-port 9000
-- 실행 명령어
$ java -jar shopping-0.0.1-SNAPSHOT.jar
--> 탄력적IP주소 주소창에 입력후 이동 확인
📘 [BookService 클래스 설명] Controller ↔ Service ↔ Repository 사이에서 데이터를 주고받는 중간 다리 역할 - Controller가 요청을 보내면 Service가 로직을 처리하고 - Repository를 통해 DB와 실제로 데이터를 주고받는다.
ModelMapper 객체 생성 - Bean ↔ Entity 간 자동 변환을 도와주는 라이브러리
package com.example.Ex02.entity;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
@NoArgsConstructor // 매개변수가 없는 생성자
@AllArgsConstructor // 매개변수가 모두 있는 생성자
@Table(name = "eTest") // 테이블 이름 새로 지정
@Entity // 클래스 이름을 보고 테이블 자동생성
public class EntityTest {
@Id // PK(Primary Key) 지정 @Entity가 붙은 클래스에는 반드시 하나 필요
private int num;
@Column(name = "irum", nullable = false)
private String name;
private String addr;
private int age;
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddr() {
return addr;
}
public void setAddr(String addr) {
this.addr = addr;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
🌈4. 인터페이스 설정
package com.example.Ex02.repository;
import com.example.Ex02.entity.EntityTest;
import org.springframework.data.jpa.repository.JpaRepository;
// JpaRepository<엔티티 클래스, 프라이머리키(PK) 타입>
// EntityTest 엔티티를 관리하고, PK 타입은 int 이므로 Integer 사용
public interface EntityRepository extends JpaRepository<EntityTest, Integer> {
}
✅ 특징
JpaRepository<EntityTest, Integer>
첫 번째 제네릭: 엔티티 클래스 (EntityTest)
두 번째 제네릭: PK 타입 (int → Integer)
JpaRepository 를 상속했기 때문에 CRUD 기능이 자동으로 제공
JpaRepository<T, ID> 는 CrudRepository<T, ID> 와 PagingAndSortingRepository<T, ID>를 상속
그래서 save, findById, findAll, deleteById 같은 CRUD 메서드가 기본 내장
@Test
@DisplayName("이름이 '윤아'인 레코드 조회")
public void findName() {
List<EntityTest> elists = entityRepository.findByName("윤아");
for(EntityTest entity : elists){
System.out.println(entity.toString());
}
}
@Test
@DisplayName("이름에 '수'가 포함된 이름 조회")
public void findNameFind(){
List<CompanyEntity> lists = companyRepository.findByNameContaining("수");
for(CompanyEntity cEntity : lists) {
System.out.println(cEntity.toString());
}
}
@Test
@DisplayName("이름에 '수'가 포함된 이름 조회 & 회사명 내림차순 조회")
public void findNameAndCompanyFind(){
List<CompanyEntity> lists = companyRepository.findByNameContainingOrderByCompanyDesc("수");
for(CompanyEntity cEntity : lists) {
System.out.println(cEntity.toString());
}
}
@Test
@DisplayName("나이가 30인 레코드 조회")
public void findAge() {
List<EntityTest> elists = entityRepository.findByAge(30);
for(EntityTest entity : elists){
System.out.println(entity.toString());
}
}
@Test
@DisplayName("나이가 30 초과인 레코드 조회")
public void findAgeOver() {
List<EntityTest> elists = entityRepository.findByAgeGreaterThan(30);
for(EntityTest entity : elists){
System.out.println(entity.toString());
}
}
@Test
@DisplayName("나이가 30 이상인 레코드 조회")
public void findAgeEqual() {
List<EntityTest> elists = entityRepository.findByAgeGreaterThanEqual(30);
for(EntityTest entity : elists){
System.out.println(entity.toString());
}
}
인터페이스
// JpaRepository<EntityTest, Integer>
// → 첫 번째 제네릭(EntityTest): 엔티티 클래스
// → 두 번째 제네릭(Integer): 프라이머리키(기본키) 타입
public interface EntityRepository extends JpaRepository<EntityTest, Integer> {
// 1. name 컬럼이 특정 값과 일치하는 레코드 조회
List<EntityTest> findByName(String name);
// 2. age 컬럼이 특정 값과 일치하는 레코드 조회
List<EntityTest> findByAge(int i);
// 3. age 컬럼이 특정 값보다 큰 레코드 조회 (>)
List<EntityTest> findByAgeGreaterThan(int i);
// 4. age 컬럼이 특정 값 이상인 레코드 조회 (>=)
List<EntityTest> findByAgeGreaterThanEqual(int i);
List<CompanyEntity> findBySalaryGreaterThanEqual(int i);
List<CompanyEntity> findByNameContaining(String 수);
List<CompanyEntity> findByNameContainingOrderByCompanyDesc(String 수);
}
메서드 네이밍 규칙 (쿼리 메서드)
findBy필드명 → 해당 필드 조건으로 조회
findBy필드명And필드명 → 여러 조건 조회
findBy필드명GreaterThan → > 조건
findBy필드명GreaterThanEqual → >= 조건
findBy필드명LessThan, Between, Like, In 등도 가능
자동으로 JPQL 생성됨
예) findByName("윤아") → 실행 SQL: select * from entity_test where name = '윤아';
예) findByAgeGreaterThan(20) → 실행 SQL: select * from entity_test where age > 20;
6-3) id조회 (primarykey)
@Test
@DisplayName("id 조회")
// PK가 num인 경우 findById()와 findByNum()은 결과가 동일하다. 하지만 findById()는 PK 전용
public void getId(){
Optional<ItemEntity> o = itemRepository.findById(50L);
System.out.println("o" + o);
}
➡️findById()는 Optional을 리턴
➡️PK가 Long 타입 이므로 findById(50L) 메서드 안 숫자에 'L' 기입
6-4) 가격 조회(primarykey)
@Test
@DisplayName("6. price조회")
// price 300보다 작은 레코드를 가격기준 내림차순 정렬 조회 출력
// Query method
public void getPrice(){
List<ItemEntity>lists = itemRepository.findByPriceLessThanOrderByPriceDesc(300);
for (ItemEntity item:lists){
System.out.println(item);
}
}
@Test
@DisplayName("7. price조회")
// price 300큰 레코드를 가격기준 오름차순 정렬 조회 출력
// Query method
public void getPrice2(){
List<ItemEntity>lists = itemRepository.findByPriceGreaterThanOrderByPriceAsc(300);
for (ItemEntity item:lists){
System.out.println(item);
}
}
package com.example.Ex02.repository;
import com.example.Ex02.entity.CompanyEntity;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import java.util.List;
import java.util.Optional;
public interface CompanyRepository extends JpaRepository<CompanyEntity, Integer> {
// 1. 전체 조회
/*@Query(value = "select * from company_entity", nativeQuery = true)*/
@Query(value = "select i from CompanyEntity i", nativeQuery = false)
List<CompanyEntity> findAllQuery();
// 2. 레코드 개수 조회
@Query("select count(company) from CompanyEntity company")
int countCompany();
// 3. 이름이 '수지'인 사람 조회
@Query("SELECT i FROM CompanyEntity i WHERE i.name = :name")
List<CompanyEntity> findByNameSuji(@Param("name") String name);
// 4. 이름에 '수'가 포함된 사람조회 & 회사이름 내림차순
@Query("SELECT i FROM CompanyEntity i WHERE i.name LIKE %:name% order by company desc")
List<CompanyEntity> findNameContainSu(@Param("name") String name);
// 5. 상세설명에 '어'들어간 레코드 찾기
@Query(value = "select i from ItemEntity i where i.itemDetail like %:itemDetail%")
List<ItemEntity> findByItemDetail(@Param("itemDetail")String itemDetail);
// 6. 상세설명에 '어'포함 & price가 300이상인 레코드 조회
@Query(value = "select i from ItemEntity i where i.itemDetail like %:itemDetail% and i.price >= :price")
List<ItemEntity> findByItemDetailPrice(@Param("itemDetail, price") String itemDetail, int price);
//8. 특정 레코드 삭제
@Modifying
@Transactional
@Query(value = "delete from item_entity where item_name = :itemname", nativeQuery = true)
void deleteItemName(@Param("itemname") String itemName);
}
delete를 할때 두개의 어노테이션이 필요한 이유
1️⃣ @Modifying — “SELECT 아님!” 표시
2️⃣ @Transactional — : “commit / rollback” 보장
: 삭제가 되면 커밋, 안되면 롤백
데이터를 바꾸는(delete/update/insert) 모든 쿼리는 트랜잭션 안에서만 안전하게 실행
-------------------------------------------------------------------------------------
-- 회원 테이블
-------------------------------------------------------------------------------------
DROP TABLE members CASCADE CONSTRAINTS;
create table members(
id varchar2(10) primary key,
name varchar2(30),
password varchar2(30),
gender varchar2(10),
hobby varchar2(70),
address varchar2(30),
mpoint number default 0
) ;
insert into members(id,name,password,gender,hobby,address)
values('kim','김철수','1234','남자','게임','서울');
insert into members(id,name,password,gender,hobby,address)
values('hong','홍길동','1234','남자','공부','부산');
insert into members(id,name,password,gender,hobby,address)
values('park','권지현','1234','여자','마라톤,공부','제주');
commit ;
col id for a6
col password for a8
col name for a8
col gender for a6
col hobby for a15
col address for a10
col job for a6
select * from members;
-------------------------------------------------------------------------------------
-- 상품 테이블
-------------------------------------------------------------------------------------
drop sequence seqprod ;
create sequence seqprod start with 1 increment by 1 nocache ;
DROP TABLE products CASCADE CONSTRAINTS;
-- name : 상품명, company : 제조 회사, image : 상품 이미지
-- stock : 재고 수량, point : 적립 포인트, inputdate : 입고 일자, category : 카테고리
create table products(
num int primary key,
name varchar2(50) not null,
company varchar2(50),
image varchar2(30),
stock int default 0,
price int default 0,
category varchar2(12),
contents varchar2(300),
point int default 0,
inputdate date default sysdate
);
-------------------------------------------------------------------------------------
insert into products(num, name, company, image, stock, price, category, contents, point, inputdate)
values(seqprod.nextval, '소보루', '샤니', 'orange.jpg', 100, 1000, 'bread', '맛있어요', 10, sysdate );
insert into products(num, name, company, image, stock, price, category, contents, point, inputdate)
values(seqprod.nextval, '크림빵', '샤넬', 'blueberry.jpg', 50, 2000, 'bread', '맛있어요', 20, sysdate );
insert into products(num, name, company, image, stock, price, category, contents, point, inputdate)
values(seqprod.nextval, '콜라', '코카', 'melon.jpg', 30, 3000, 'beverage', '탁쏩니다', 30, sysdate );
insert into products(num, name, company, image, stock, price, category, contents, point, inputdate)
values(seqprod.nextval, '사이다', '칠성', 'kiui.jpg', 40, 4000, 'beverage', '탁쏩니다', 40, sysdate );
insert into products(num, name, company, image, stock, price, category, contents, point, inputdate)
values(seqprod.nextval, '환타', '코카', 'melon.jpg', 50, 5000, 'beverage', '탁쏩니다', 50, sysdate );
insert into products(num, name, company, image, stock, price, category, contents, point, inputdate)
values(seqprod.nextval, '치킨', '네네', 'pine.jpg', 50, 5000, 'chicken', '맛없어요', 60, sysdate);
commit ;
col name for a6
col company for a6
col category for a8
col stock for 999
col num for 99
col point for 99
col price for 9999
col contents for a10
col image for a14
select * from products;
-------------------------------------------------------------------------------------
-- 주문 (매출) 테이블
-------------------------------------------------------------------------------------
drop sequence seqoid ;
create sequence seqoid start with 1 increment by 1 nocache ;
DROP TABLE orders CASCADE CONSTRAINTS;
-- oid : 주문(송장) 번호, mid : 회원 번호, orderdate : 주문 일자
create table orders(
oid number primary key,
mid varchar2(10) references members(id) on delete set null,
orderdate date default sysdate
);
select * from orders;
------------------------------------------------------------------------------------------------------
-- orderdetails : 주문 상세 테이블
-------------------------------------------------------------------------------------
drop sequence seqodid;
create sequence seqodid start with 1 increment by 1 nocache ;
-- oid : 주문번호, pnum : 상품 번호, qty : 주문 수량
drop table orderdetails purge ;
create table orderdetails(
odid number primary key,
oid number references orders(oid) on delete cascade,
pnum number references products(num) on delete set null,
qty number
);
select * from orderdetails;
@GetMapping("/pinsert.prd")
public String insertForm(HttpSession session, @ModelAttribute("pDto") ProductsDto pDto){
if(session.getAttribute("loginInfo") == null){
// 로그인 안 되어 있으면 → 로그인 페이지로 이동
session.setAttribute("destination", "redirect:/pinsert.prd");
return "redirect:/login.mb";
}
return "products/productInsert"; // 로그인 되어 있으면 삽입폼으로
}
세션(HttpSession)은 로그인 유지 + 권한 제어 + 이전 페이지 기억 에 활용된다.
loginInfo : 로그인 사용자 정보 저장
destination : 로그인 후 되돌아갈 주소 저장
invalidate() : 로그아웃 시 세션 삭제
🌈8. 장바구니 구현 (MallController / mallList.html)
상품 상세에서 주문 버튼 주문버튼 클릭시 장바구니 이동
productContent.prd ➡️ mall.list 이동
(1) MyCartDto
package com.example.Ex02.dto;
import java.util.HashMap;
import java.util.Map;
public class MyCartList {
private Map<Integer, Integer> orderlists = null;
public MyCartList(){
orderlists = new HashMap<Integer, Integer>(); // key, value
// 3번 상품, 2개 주문
// 1번 상품, 5개 주문
}
// 장바구니 있는 상품을 더 추가할 경우
public void addOrder(int pnum, int oqty){
// orderlists : Map<Integer, Integer>
// key = 상품번호(pnum), value = 주문수량(qty)
if(orderlists.containsKey(pnum)){ // ✅ 이미 장바구니에 같은 상품이 있는 경우
Integer qty = orderlists.put(pnum, oqty);
int addQty = qty + oqty;
orderlists.put(pnum,addQty); // 기존 수량 + 새 수량으로 덮어쓰기
}else{// ✅새상품이면
orderlists.put(pnum,oqty); // 그대로 추가
}
}
public Map<Integer,Integer> getAllOrderlists(){
return orderlists;
}
}
(2) mallController
1. 장바구니 구현 컨트롤러에 로그인 세션 가져오기 (로그인 여부확인)
2. 장바구니 세션 생성
// productContent.prd => 주문버튼 클릭시 장바구니 이동
@PostMapping(value = "/add.mall")
public String add(ProductsDto product, HttpSession session,
@RequestParam(value = "whatColumn", required = false) String whatColumn,
@RequestParam(value = "keyword", required = false) String keyword,
@RequestParam(value = "page",defaultValue = "1") int page
){
System.out.println("product.getNum()" + product.getNum());
System.out.println("product.getOrerqty()" + product.getOrderqty());
// memberController에서 설정한 loginInfo를 get으로 불러와서 사용
// 1. 로그인 여부 확인 (세션에 "loginInfo"가 없으면 로그인 안된 상태)
if(session.getAttribute("loginInfo") == null){
String encodeKeyword = keyword != null ? URLEncoder.encode(keyword, StandardCharsets.UTF_8) : "";
session.setAttribute("destination", "redirect:/pcontent.prd?" +
"num="+product.getNum()
+"&page="+page
+"&whatColumn="+whatColumn
+"&keyword=" +encodeKeyword);
return "redirect:/login.mb";
}else{
// 2. 로그인 된 경우 → 장바구니 처리
// 장바구니 세션 설정 : mycart
MyCartList mycart = (MyCartList) session.getAttribute("mycart");
System.out.println("mycart1 : " + mycart);
if(mycart == null){ // 3. 장바구니가 없다면 == > 장바구니 생성
mycart = new MyCartList(); // "장바구니 객체" 생성
}
System.out.println("mycart2 : " + mycart);
// 4. 장바구니에 상품 추가
mycart.addOrder(product.getNum(), product.getOrderqty());
// 5. 장바구니를 계속 끌고다닐수 있도록 세션 설정
session.setAttribute("mycart", mycart);
return "redirect:/list.mall";
}
}
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--orders.xml-->
<mapper namespace="com.example.Ex02.mapper.OrderMapper">
<insert id="insertOrder" parameterType="com.example.Ex02.dto.OrderDto">
insert into orders (oid, mid, orderdate)
values (seqoid.nextval, #{mid}, sysdate)
</insert>
<!--가장 큰 oid값 -->
<select id="getMaxOid" resultType="int">
select max(oid)
from orders
</select>
<!--주문자 주문목록 찾기-->
<select id="orderMall">
select * from orders
where mid = #{id}
order by oid desc
</select>
<!--주문 상세보기-->
<select id="showDetail">
select num as pnum, name as pname, qty, price, qty*price as amount
from (orders o inner join orderdetails od
on o.oid = od.oid) inner join products
on pnum = num and o.oid = #{oid}
</select>
</mapper>
Path path = Paths.get(uploadDir, filename);
try {
Files.delete(path); // 파일 없으면 NoSuchFileException
System.out.println("삭제 성공");
} catch (IOException e) {
e.printStackTrace(); // 파일 없거나 권한 문제 모두 예외 처리
}
(2) Files.deleteIfExists(Path)
파일 없으면 false 반환, 안전하게 삭제
👉 deleteIfExists는 존재하지 않아도 예외가 안 터지니까 실무에서 가장 많이 씀.
Path path = Paths.get(uploadDir, filename);
try {
Files.deleteIfExists(path); // 파일이 없으면 false 반환
System.out.println("삭제 성공 또는 파일 없음");
} catch (IOException e) {
e.printStackTrace(); // 접근 권한 문제 등만 잡으면 됨
}