20220831 [Spring Boot]

Yeoonnii·2022년 8월 31일
0

TIL

목록 보기
16/52
post-thumbnail

👨‍🏫컨트롤러 서비스 저장소 왔다갔다 하는거 연습해야 한다
화면에 어떤 정보 보낼지 고민,
상황별로(암호변경시) 어떤정보가 필요한지 어떤 정보들을 보낼지 고민!
많은 연습을 해야한다 연습만이 살길…

로그인(세션)

세션 : 기록하고 싶은 일들을 세션에 보관한다
과거에 했던 행적을 기록해서 유지하며 세션이 유지되는 시간 기본값은 30분이다
redis 사용하면 좋은데 지금은 파일기반 mongoDB로 실습진행!

  • 로그인 후 30분이 지나면 그 세션값은 자동적으로 소멸된다
  • 세션 기록정보가 있으면 ➡️ 로그인 한 사람이구나!
  • 기록정보가 없으면 ➡️ 로그인 하지 않았구나!

메모리 기반의 세션, DB(파일) 기반의 세션, DB메모리기반 세션

  • 메모리 기반 세션 : 눈으로 데이터 확인이 어렵다
    컴퓨터 켜져 있는 동안만 메모리 저장 ➡️ 속도 측면에서는 메모리 기반 세션이 빠르다
  • DB(파일)기반 세션 : 파일로 저장되어 메모리가 눈으로 확인 가능하다
    ex) mongodb
  • In-Memory DB: 디스크(Disk) 대신 메모리(Memory)를 사용
    전원 꺼지면 메모리 사용 불가
    ex) redis, memchaed
    🌎참고 RDBMS vs NoSQL vs InMemory

📁 pom.xml

세션용 라이브러리 추가

<!-- mongodb session -->
<dependency>
		    <groupId>org.springframework.session</groupId>
    		<artifactId>spring-session-data-mongodb</artifactId>
		</dependency>

📁 MemberController.java

  • httpSession.setAttribute("키", "실제값");
  • MemberController.java 에서 로그인 성공 후 세션에 적절한 값을 추가한다
    mService loginMember ➡️ 반환값으로 member를 받는다

    반환값으로 member를 받는 이유는 return값을 member로 줘야 sessionid를 저장 가능하기 때문이다!
    memberservice에서 쿼리 작성하여 로그인 해도 되지만 어떤 방법을 사용하던 로그인 후 return값을 int로 주는 경우는 session에 정보를 저장할 수 없다(누구인지 정보가 없는데 저장할 수는 없기 떄문)

@Autowired
    HttpSession httpSession;
...
    // 로그인 화면 이동(GET)
    // 127.0.0.1:8080/ROOT/join.do
    @GetMapping(value = "/login.do")
    public String loginGET() {
        return "login";
    }

    // 로그인 버튼(POST)
    @PostMapping(value = "/login.do")
    public String loginPOST(@ModelAttribute Member member) {
        // 1. 전송되는 값 확인
        System.out.println("전송값" + member.toString());

        // 2. service 호출해서 전송
        Member retmMember = mService.loginMember(member);
        // 3. 결과값 확인 후 처리
        // 4. 적절한 페이지로 이동(GET으로 이동)
        if (retmMember != null) { // 로그인 된 경우
            System.out.println("로그인값" + retmMember.toString());

            // 세션에 적절한 값을 추가함. 유지 시간 기본값(30분동안) 유지
            httpSession.setAttribute("SESSION_ID", retmMember.getId());
            httpSession.setAttribute("SESSION_NAME", retmMember.getName());

            return "redirect:/home.do";
        } // 로그인 되지 않은경우
        return "redirect:/member/login.do";
    }

📁 login.html

암호가 있으니 get으로 보내면 안된다! POST로 보내기

<!DOCTYPE html>
<html lang="ko" xmlns:th="http://www.thymeleaf.org">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>로그인</title>
</head>

<body>
    <div style="border: 1px double #0000006e; padding: 20px;">
        <h3>로그인</h3>

        <form th:action="@{/member/login.do}" method="post">
            <label style="display: inline-block; width: 100px;">아이디</label><input type="text" name="id" /><br />
            <label style="display: inline-block; width: 100px;">암호</label><input type="password" name="password" /><br />
            </hr>
            
            <input type="submit" value="로그인" />
        </form>
    </div>
</body>

</html>

📁 MemberService.java

memberservice.java에서 쿼리 작성하여 로그인 해도 된다
하지만 return값은 반드시 member로 와야 session에 id를 저장가능하다

    // 로그인
    public Member loginMember( Member member ){
        try {
			return mRepository.selectMemberLogin(member.getId(), member.getPassword());
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

📁 MemberRepository.java

MongoRepository<Member, String> ➡️ <엔티티, 엔티티id타입>

  • value = 조건 값 _id, password
  • fields = (Member에서)가져올 내용 _id, name
  • value 안에 , 로 연결된 값들은 and 조건이다
...
@Repository
public interface MemberRepository extends MongoRepository<Member, String>{
...

// 로그인용
    @Query(value = "{_id : ?0, password : ?1}", fields = "{_id : 1, name : 1}")
    public Member selectMemberLogin(String id, String pw);

📁 HomeController.java

  • 홈 화면은 세션이 필요하다 ➡️ 사용자의 로그인 여부를 파악하여 홈화면 다르게 구현하기 위해
  • HomeController.java에서도 세션 사용하여 로그인 여부를 파악 한 후 return한다
  • MemberController.java 에서 로그인시 키값을 두개 넣었다!
    SESSTION_ID, SESSTION_NAME
  • HttpSession.getAttribute(String arg0) : Object ➡️ arg0은 string 타입이다
@Autowired
    HttpSession httpSession;
...
// return 될 파일명은 string 이니까 string 사용
    public String homeGET() {
        
        String userid = (String) httpSession.getAttribute("SESSION_ID");

        if(userid == null){
            System.out.println("로그인 안됨");
        } else {
            System.out.println("로그인 됨");
        }
            return "home";  //=> resource/templates/home.html
        }

📁 home.html

  • 홈화면 구성시 로그인(세션)기록 여부에 따라 페이지를 다르게 구현한다
  • 로그인/회원가입 ⇒ 로그인 안된경우 출력
  • 로그아웃/마이페이지 ⇒ 로그인 된 경우 출력
  • th:if 사용하여 로그인 여부에 따라 화면을 출력한다
<!DOCTYPE html>
<html lang="ko" xmlns:th="http://www.thymeleaf.org">
...
<body>
    <h3>홈화면</h3>
	
  // 로그인 안된 경우
    <th:block th:if="${sessing.SESSION_ID == null}">
        <a th:href="@{/member/login.do}">로그인</a>
        <a th:href="@{/member/join.do}">회원가입</a>
    </th:block>
    
  // 로그인 된 경우
    <th:block th:if="${sessing.SESSION_ID != null}">
    <a th:href="@{/member/logout.do}">로그아웃</a>
    <a th:href="@{/member/mypage.do}">마이페이지</a>
    </th:block>

    <a th:href="@{/board/boardlist.do}">게시판</a>
    <a th:href="@{/item/seller.do}">판매자</a>
    
</body>
...

로그아웃(세션)

로그아웃 get으로 보내면 안된다! post사용
세션 메모리기반 ⇒ 데이터 확인이 어렵다

📁 MemberController.java

  • 로그아웃시 기존의 세션 내용 지우기
    ➡️ 세션의 내용을 (비우는)null이 아니라 세션을 새로 시작하는게 맞는 방법이다
  • 세션 초기화 = httpSession.invalidate();
// 로그아웃
    @PostMapping(value = "/logout.do")
    public String logoutPost() {
        httpSession.invalidate(); // 세션 초기화
        return "redirect:/home.do";
    }

📁 Application.java

  • @Autowired ➡️ bean에 의해 객체 생성이 되어있어 사용가능
  • @Bean ➡️ 서버 구동시 자동으로 객체를 생성하는 것!
    보기 편하지만 나중에 한계가 있다
  • @Bean 붙어있는경우 객체가 생성되어 있구나 하고 이해하기

📁 Boot20220824Application.java

  • jackson은 내용이 보여서 편리하지만 원래 session은 내용을 볼 용도로 사용하는게 아니다!
    jacksonentity가 안들어가고 jdkentity가 통으로 들어간다
  • jdk에서 entity를 통으로 꺼내어 필요한 정보만 꺼내 쓴다
  • MongoDB 세션저장시
    컬렉션명, 유지 시간 = ( ) + 클래스명 obj = new 생성자(유지 시간)
    일반웹인 경우 대부분 jdk사용하며, json문서인 경우 Jackson방식 사용
  1. JdkMongoSessionConverter ⇒ 속성값이 byte이기 때문에 확인 불가
    • collectionName = DB에 생성될 컬렉션 이름
    • EnableMongoHttpSession.maxInactiveIntervalInSeconds : int
      = 시간 (600이 10분)

@EnableMongoHttpSession(collectionName = "boot_sessions", maxInactiveIntervalInSeconds = 60*30 )
...
@Bean
	public JdkMongoSessionConverter jdkMongoSessionConverter() {
		return new jdkMongoSessionConverter(Duration.ofMinutes(30))
	}

DB에서 attr이 데이터 부분이다
entityattr byte[] 형태로 온다
로그인 한 사용자는 로그인 정보가 추가로 저장되었기 때문에 데이터가 더 많은것을 확인 할 수 있다.

  1. JacksonMongoSessionConverter

    json문서인 경우 이 방식 사용! json 형태로 저장되며 내용도 확인이 가능
    하지만 json문서에서는 token방식을 더 많이 사용한다

// jackson방식
	
	@Bean
	public JacksonMongoSessionConverter jacksonMongoSessionConverter() {
		return new JacksonMongoSessionConverter();
	}

게시판 조회수 증가 문제(세션 처리)

📁 BoardController.java

@Autowired 사용시 @bean으로 객체가 생성되어 있음을 알고있어야 한다
메모리 ➡️ @Bean mongodb jdk

✔️ 조회수 1증가 과정(BoardController.java)
1. 글 목록 조회에서 세션에 BOARD_HIT값을 true로 설정
httpSession.setAttribute("BOARD_HIT", true);
2. 상세페이지 1개 조회에서 httpSession의 BOARD_HIT값을 가져온 후
3. if(isHit == true) 이면
조회수 1 증가 bService.boardUpdateHit(no);
+ BOARD_HIT값을 false로 변경 httpSession.setAttribute("BOARD_HIT", false);
➡️ 이후 BOARD_HIT값을 true로 변경하려면 글목록 페이지로 이동해야
글 목록 페이지 로딩시 세션의 BOARD_HIT값이 다시 true로 설정된다.

...
	@Autowired
	HttpSession httpSession;
...
    // 상세페이지 1개 조회
    @GetMapping(value = "/boardone.do")
    public String boardOneGET(Model model,
            @RequestParam(name = "no", defaultValue = "0") long no) {
        if (no == 0) { // 번호가 없는경우, 오류처리
            return "redirect:/board/boardlist.do";
        }
		// 목록에서 클릭시 조회수 1증가 (최초 1회)
        boolean isHit = (boolean) httpSession.getAttribute("BOARD_HIT");
        // 0. 조회수 증가 (조회수가 증가된 게시물을 가져와야하니 맨 위에 위치)
        // 세션으로 처리
       if(isHit == true){
           bService.boardUpdateHit(no);
           // 목록으로 가야 true로 바뀐다
           httpSession.setAttribute("BOARD_HIT", false);
...
    //글 목록조회
    @GetMapping(value = "/boardlist.do")
    public String boardListGET(Model model,
            @RequestParam(name = "txt", defaultValue = "", required = false) String txt,
            @RequestParam(name = "page", defaultValue = "1", required = false) int page) {
        // 목록에서 세션에 BOARD_HIT값을 true로 설정
        httpSession.setAttribute("BOARD_HIT", true);
...

이전글/다음글 이동시 조회수 증가(세션)

📁 BoardController.java

  1. 상세페이지 1개 조회 메서드에서 조회시 "BOARD_HIT" = false설정시점에 "BOARD_NO" = no로 세팅한다.
  2. BOARD_NO를 변수 boardNo 로 설정 후
    long boardNo = (long) httpSession.getAttribute("BOARD_NO");
  3. 이전글/다음글로 이동하여 if(no != boardNo) 조건을 만족하는 경우
  4. 조회수를 1 증가 bService.boardUpdateHit(no);
    + BOARD_NO를 이동된 글의 no로 재설정한다 httpSession.setAttribute("BOARD_NO", no);
// 이전글 다음글로 이동시 조회수 증가
       long boardNo = (long) httpSession.getAttribute("BOARD_NO");
       if(no != boardNo){
        bService.boardUpdateHit(no);
        httpSession.setAttribute("BOARD_NO", no);
       }

마이페이지

📁 MemberController.java

  • 세션에서 SESSION_ID를 가져온 후 로그인 된 사용자인 경우만 접근 가능하게 조건을 설정해 준다
    ➡️ 나중에 시큐리티 사용하면 세션관련 코드 작성 안해도 됨 지금은 원리를 이해하는 과정
  • 로그인 된 사용자가 마이페이지로 이동시 처음 뜨는 화면은 마이페이지 접속시 주소 menu뒤에 아무번호도 붙지 않는다면 1로 설정한다
  • menu가 1인경우
// 마이페이지 생성
    // http://127.0.0.1:8080/ROOT/member/mypage.do
    @GetMapping(value = "/mypage.do")
    public String mypageGET(){
        // 세션에서 정보 가져오기
        String userid = (String) httpSession.getAttribute("SESSION_ID");
        // 로그인 되지 않았다면 로그인 페이지로 이동
        if(userid == null){
            return "redirect:/member/login.do";
        }
        if(menu == 0){
            //처음 마이페이지 접속시 주소 menu뒤에 아무번호도 붙지 않으면 1로 설정 
            return "redirect:/member/mypage.do?menu=1"; 
        }
        return "mypage";
    }

📁 mypage.html

<!DOCTYPE html>
<html lang="ko" xmlns:th="http://www.thymeleaf.org">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>마이페이지</title>
</head>

<body>
    <div style="border: 1px double #0000006e; padding: 20px;">
        <h3>마이페이지</h3>
        <hr />

        <a th:href="@{/member/mypage.do?(menu=1)}"><button>정보변경</button></a>
        <a th:href="@{/member/mypage.do?(menu=2)}"><button>암호변경</button></a>
        <a th:href="@{/member/mypage.do?(menu=3)}"><button>회원탈퇴</button></a>
        <hr />

        <div th:if="${#strings.toString(param.menu) == '1'}">
            정보변경
            <hr />
        </div>
        <div th:if="${#strings.toString(param.menu) == '2'}">
            암호변경
        </div>
        <div th:if="${#strings.toString(param.menu) == '3'}">
            탈퇴하기
        </div>                
    </div>
</body>

</html>

<body>에 footer 추가

📁 footer.html

<!DOCTYPE html>
<html lang="ko" xmlns:th="http://www.thymeleaf.org">

<footer th:fragment="footerFragment">
    <p>copyright 2022</p> 
</footer>

</html>

📁 mypage.html

<body> 하단에 footer추가
<div th:replace="~{파일명 :: fragment이름}"></div>

<html lang="ko" xmlns:th="http://www.thymeleaf.org">
...
       
        <div th:replace="~{footer :: footerFragment}"></div>
...

회원정보수정

📁 entity / Member.java

암호변경을 위해 entity에 암호변경용 임시변수 생성
@Transient ➡️ 임시변수 생성시 사용, DB에는 들어가지 않는 항목이다

@Transient
    private String password1 = null; //암호변경 임시변수

📁 mypage.html

  • 화면이 로딩 되었을때 정보가 입력되어 있어야 한다
  • 3개 각각의 메서드를 생성해도 되지만 if문으로 한번에 처리
    MemberController.java에서 if(menu=1)..else(menu=2)..else(menu=3)을 사용하기 위해 메뉴별로 반복문을 실행한다<div th:if="${#strings.toString(param.menu) == '1'}">를 사용하여 <form th:action="@{/member/mypage.do(menu=1)}" method="post">
  • MemberService 회원정보 조회시 return된 obj는 1개이니 반복문 돌릴 필요 없음
th:value="${obj.name}"

위와같은 형태로 담아 바로 출력한다

  • 보여지는 화면만 다를 뿐 회원정보 수정시 MemberController 내부의 같은 메서드로 보낸다
    action 부분의 파라미터만 다를 뿐 멤버 컨트롤러의 if문 에 따라 다르게 처리된다
    컨트롤러를 3개 만들기 싫어서 @RequestParam으로 menu 받고 컨트롤러 안의 같은 메서드로 넣고 if문으로 3개 동시에 처리

😧❓ mypage.html에서 메뉴별 페이지 생성시 주소설정

  • 웹보드 : <form th:action="@{/member/mypage.do(menu=1)}”
    (menu=1) ⇒ 컨트롤러에서 메뉴별 if사용하려고 한것
  • 나 : <form th:action="@{/member/mypage.do?menu=1}”
    menu=1 ⇒ 이렇게 작성하면 컨트롤러에서 메뉴 1 post 따로 2 post따로 만들어야 된다고 하지만 작동은 된다..
<!DOCTYPE html>
<html lang="ko" xmlns:th="http://www.thymeleaf.org">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>마이페이지</title>
</head>

<body>
    <div style="border: 1px double #0000006e; padding: 20px;">
        <h3>마이페이지</h3>

        <div th:text="| 아이디 : ${session.SESSION_ID} |"></div>
        <div th:text="| 이름 : ${session.SESSION_NAME} 님 로그인중 |"></div>
        <hr />

        <a th:href="@{/member/mypage.do?(menu=1)}"><button>정보변경</button></a>
        <a th:href="@{/member/mypage.do?(menu=2)}"><button>암호변경</button></a>
        <a th:href="@{/member/mypage.do?(menu=3)}"><button>회원탈퇴</button></a>
        <hr />

        <div th:if="${#strings.toString(param.menu) == '1'}">
            정보변경
            <hr />
            <form th:action="@{/member/mypage.do(menu=1)}" method="post">
                <label style="display: inline-block; width: 100px;">이름</label><input type="text" name="name" th:value="${obj.name}" /><br />
                <label style="display: inline-block; width: 100px;">연락처</label><input type="text" name="phone" th:value="${obj.phone}" /><br />
                <hr />
                <input type="submit" value="변경하기" />
            </div>
            <div th:if="${#strings.toString(param.menu) == '2'}">
                <form th:action="@{/member/mypage.do?(menu=2)}" method="post">
                    <label style="display: inline-block; width: 100px;">현재암호</label><input type="password" name="password" /><br />
                    <label style="display: inline-block; width: 100px;">변경암호</label><input type="password" name="password1" /><br />
                    <!-- 아래는 유효성검사용 -->
                    <label style="display: inline-block; width: 100px;">변경암호확인</label><input type="password"  /><br />
                    <hr />
                    <input type="submit" value="암호변경하기" />
                </form>
            </div>
            <div th:if="${#strings.toString(param.menu) == '3'}">
                <form th:action="@{/member/mypage.do?(menu=3)}" method="post">
                    탈퇴하려면 현재암호를 입력하세요 <br />
                    <label style="display: inline-block; width: 100px;">현재암호</label><input type="password" name="password" /><br />
            </form>
        </div>                

        <!-- <div th:replace="~{파일명 :: fragment이름}"></div> -->
        <div th:replace="~{footer :: footerFragment}"></div>
    </div>
</body>

</html>

📁 MemberController.java

  • 마이페이지 생성시 데이터가 입력되어 있어야 함
    ➡️ 마이페이지 생성시 obj로 member 데이터를 불러온다

    모델 생성Model modelmodel에 조회한 member데이터를 담아준다

if(menu ==1){
            Member member = mService.selectMemberOne(userid);
            model.addAttribute("obj", member);
        }
  • 회원정보 수정 메서드 생성 : 세션에서 가져온 유저 아이디 주면 멤버반환
    1. SESSION_ID 가져와서 userid에 담는다 (회원정보 수정조건)
    2. userid가 존재하는 경우 member.setId(userid)
    3. if(menu == 해당메뉴번호)의 경우에 맞게 mServicemember를 넣어 return값을 반환한다
// 마이페이지 생성
    // http://127.0.0.1:8080/ROOT/member/mypage.do
    @GetMapping(value = "/mypage.do")
...
        if(menu == 1){
            Member member = mService.selectMemberOne(userid);
            model.addAttribute("obj", member);
        }
    // http://127.0.0.1:8080/ROOT/member/mypage.do?&menu=1
    // 회원정보 수정하기
    @PostMapping(value = "/mypage.do")
    public String mypagePOST(
        @RequestParam(name = "menu") int menu,
        @ModelAttribute Member member
        ){
            System.out.println("회원정보수정하기" + member.toString());
            // 1,2,3번 모두 session의 id정보가 필요하다
            String userid = (String) httpSession.getAttribute("SESSION_ID");
            if( userid == null ){
                return "redirect:/member/login.do";
            }
            member.setId(userid);
            if( menu == 1 ){ //회원정보 변경시
                // 성공하든 실패하든 이동하지 않으니 반환값을 받을 필요 없다
                mService.updateMember(member);
                return "redirect:/member/mypage.do?menu=1";
            } else if( menu == 2 ){ //암호변경시
                mService.updateMemberPassword(member);
                return "redirect:/member/mypage.do?menu=2";
            } else if( menu ==3 ){ //회원탈퇴시
                mService.deleteOneMember(member);
                return "redirect:/member/mypage.do?menu=3";
        }
        return "redirect:/member/mypage.do?menu=1";
    }

📁 MemberService.java

  • 회원정보조회 ➡️ String id가 오면 저장소에서 조회 후 회원 객체 return
  • 회원정보수정 ➡️ member가 오면 Query조건에 맞는 데이터 조회 후 변경항목 변경 후 short값 return
  • 회원삭제(탈퇴) ➡️ member가 오면 Query조건에 맞는 데이터 조회 후 데이터 삭제 후 int값 return
  • 암호변경
    ➡️ 1. member가 오면 this.loginMember로그인 처리후 member return
    2. retmember != null인 경우 getId()로 일치하는 member데이터를 조회하여 새로운 Member retmember1에 담는다
    3. 사용자가 입력한 변경할 비밀번호member.getPassword1retmember1setPassword 해준다
    4. 저장소에 저장후 int 형태로 return

😧❓ 암호변경시 로그인 처리, updateMemberPassword 에서 온 멤버는 어디서 넣어줌?
@ModelAttribute Member 에서는 entity 형태로 가져옴
암호 변경시 사용자가 입력한 name="password” name="password1” 데이터 가져오고 entity 형태의 member 가져오지만 나머지는 null비어있는 형태이다

// 회원정보조회 
    public Member selectMemberOne(String id){
        try {
            return mRepository.findById(id).orElse(null);
            
        } catch (Exception e) {
            e.printStackTrace();;
            return null;
        }
    }
    // 회원정보수정
    public short updateMember( Member member ){
        try {
            // 조건
            Query query = new Query();
            Criteria criteria = Criteria.where("_id").is(member.getId());
            query.addCriteria(criteria);

            // 이름과 연락처만 변경
            Update update = new Update();
            update.set("name", member.getName());
            update.set("phone", member.getPhone());

            // (조건, 변경값, 클래스)
            // Class<T> => 타입 => Member.class
            UpdateResult result = mongoTemplate.updateFirst(query, update, Member.class);
            if(result.getModifiedCount() == 1L){
                return 1;
            }
            return 0;
        } catch (Exception e) {
            e.printStackTrace();;
            return -1;
        }
    }
    // 회원 삭제
    public int deleteOneMember( Member member ){
        try {

            Query query = new Query();
            Criteria criteria = Criteria.where("_id").is(member.getId());
            query.addCriteria(criteria);
        
            DeleteResult result = mongoTemplate.remove(query, Member.class);
            if(result.getDeletedCount() == 1L){
                return 1;
            }
            return 0;
        } catch (Exception e) {
            e.printStackTrace();;
            return -1;
        }
    }
    // 암호변경
    public int updateMemberPassword(Member member){
        try {
            // 보안을 위한 로그인 처리
            Member retmember = this.loginMember(member);
            if(retmember != null){
                // 일치한 경우 암호 수정

                //1. 변경하기위한 회원정보 조회 => 변경하려면 기존 회원정보 가져와야함
                // id 가져오기
                Member retmember1 = mRepository.findById(member.getId()).orElse(null);

                // 2. 현재암호를 password1로 변경
                retmember1.setPassword(member.getPassword1());

                // 3. 다시 저장
                mRepository.save(retmember1);
            }
            return 0;
        } catch (Exception e) {
            e.printStackTrace();;
            return -1;
        }
    }
mRepository.delete(entity);

판매자 페이지

🧪 부트스트랩 사용하기

https://getbootstrap.com/

다운로드 후 static 안에 다운받은 파일을 넣어준다

<head>태그 안에 넣고 <body>에서 <div>태그로 적용

    <link rel="stylesheet" th:href="@{/css/bootstrap.css}" />
    <script th:src="@{/js/bootstrap.js}"></script>

📁 seller.html

<!DOCTYPE html>
<html lang="ko" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>판매자</title>
    <link rel="stylesheet" th:href="@{/css/bootstrap.css}" />
    <script th:src="@{/js/bootstrap.js}"></script>
</head>

<body>
    <div class="container" style="border : 1px solid #cccccc;">
    <a href="@{/item/selectlist.do}">물품조회</a>
    <a href="@{/item/insertbatch.do}">일괄추가</a>
</div>
</body>
</html>

🤯 주소 오류


💡 <a href="@{/item/selectlist.do}">물품조회</a>로 작성되어있어 작동하지 않았다
<a th:href="@{/item/selectlist.do}">물품조회</a>로 수정해주니 오류없이 동작한다

📁 ItemController.java

  • <a href="@{/item/insertbatch.do}">일괄추가</a> 생성
  • model로 하면 엔티티 형태로 입력이 가능한데 아래와 같은 경우는 같은name끼리 데이터를 담을 배열을 만들었다 => name별 알맞은 형태의 배열로 담는다
  • itemservice.java에서 반복자Iterable를 실행했기 때문에 html의 name 값이 중복된다!
    배열에 담아 받아야 함
...
@Controller
@RequestMapping(value = "/item")
public class ItemController {

    @Autowired
    ItemService itemService;

    @GetMapping(value = "/seller.do")
    public String sellerGET(){
        return "seller";  //seller.html파일 
    }

    // 컨트롤러 생성시 이동된 주소 가져와서 작성하면 편합니다
    @GetMapping(value="/insertbatch.do")
    public String insertbatchGET() {
        return "insertbatch";
    }

    // 
    @PostMapping(value="/insertbatch.do")
    public String insertbatchPOST(
        // 반복자로 출력되기 때문에 다 배열로 온다
        @RequestParam(name = "name") String[] name,
        @RequestParam(name = "content") String[] content,
        @RequestParam(name = "price") Long[] price,
        @RequestParam(name = "quantity") Long[] quantity,
        @RequestParam(name = "image") MultipartFile[] file) throws IOException {
            
            // 새 배열 생성
            List<Item> list = new ArrayList<>();
            for( int i=0; i<name.length; i++ ){
                Item item = new Item();

                item.setName( name[i] );
                item.setContent( content[i] );
                item.setPrice( price[i] );
                item.setQuantity( quantity[i] );

                item.setFilename( file[i].getOriginalFilename() );
                item.setFilesize( file[i].getSize() );
                item.setFiletype( file[i].getContentType() );
                item.setFiledata( file[i].getBytes() );  //throws IOException

                list.add(item);
            }
            
            itemService.insertbatch(list);
            return "insertbatch";
    }
}

📁 insertbatch.html

  • 반복문으로 입력

    th:value="|물품명${i}|” ➡️ 문자 입력시
    th:value="${i}+1” ➡️ 숫자 입력시

  • entity에 맞는 name값 주기
<!DOCTYPE html>
<html lang="ko" xmlns:th="http://www.thymeleaf.org">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>물품일괄추가</title>
    <script th:src="@{/js/bootstrap.js}"></script>
</head>

<body>
    <div>
        <!-- 이미지 첨부는 enctype="multipart/form-data" -->
        <form th:action="@{/item/insertbatch.do}" method="post" enctype="multipart/form-data">
            <!-- 1부터 2까지 반복 => 화면에 2줄 출력된다 -->
            <th:block th:each="i : ${#numbers.sequence(1,2)}">
                <input type="text" name="name" placeholder="물품명" th:value="|물품명${i}|" />
                <input type="text" name="content" placeholder="물품내용" th:value="|내용${i}|" />
                <input type="text" name="price" placeholder="물품가격" th:value="${i}+100" />
                <input type="text" name="quantity" placeholder="물품수량" th:value="${i}+20" />
                <!-- 파일은 엔티티 변수로 맞추면 안된다! 한번에 못들어감 -->
                <input type="file" name="image" />
                <br />
            </th:block>
            <hr />
            <input type="submit" value="물품일괄추가" />
        </form>
    </div>
</body>
</html>

🤯 status=500 오류

<th:block th:each="i : ${numbers.sequence(1,2)}"> numbers앞에 #를 입력해주지 않아 발생한 오류였다
<th:block th:each="i : ${#numbers.sequence(1,2)}">로 변경해주니 오류없이 실행된다

📁 ItemRepository.java

저장소 생성

package com.example.repository;

import org.springframework.data.mongodb.repository.MongoRepository;

import com.example.entity.Item;

public interface ItemRepository extends MongoRepository<Item, Long>{
    
}

📁 ItemService.java

MongoRepository.saveAll(Iterable<S> entities) : List<S>
➡️ 반복자=Iterable<S> entities 라는 말은 list도 가능하다는 뜻이다

@Autowired ItemRepository iRepository;

        // [저장소] 사용하여 저장
        public int insertbatch( List<Item> list ){
            try {
                List<Item> retlist = iRepository.saveAll(list);
                if(retlist.size() == list.size()){
                    return 1;
                }
                return 0;
                
            } catch (Exception e) {
                e.printStackTrace();
                return -1;
            }
        }

0개의 댓글