20220920 [Spring Boot, H2DB, MyBatis]

Yeoonnii·2022년 9월 20일
0

TIL

목록 보기
30/52
post-thumbnail

📌 권한에 따른 로그인/로그아웃 결과

📁 SecurityConfig.java

현재 설정값
defaultSuccessUrl("/home.do")
⇒ 권한에 상관없이 모든 아이디가 로그인 성공하면 /home.do로 이동
logoutSuccessUrl("/home.do")
⇒ 권한에 상관없이 로그아웃 성공하면 /home.do로 이동

로그인/로그아웃 후 필요한 기능, 권한에 따라서 이동하는 페이지를 다르게 구현하기

로그인 시 successHandler(successHandler)
로그아웃 시 logoutSuccessHandler(LogoutSuccessHandler)
➡️ Handler이니까 패키지로만 들어갈 수 있다

핸들러 Handler 를 사용하면 유동적으로 권한에 따라 페이지를 설정할 수 있기 때문에 고정적인 주소를 지정하여 사용하는defaultSuccessUrl("/home.do") 보다 한계가 덜하다

@Bean
    public SecurityFilterChain filterChain(HttpSecurity http)
        throws Exception {

            // 로그인 페이지 설정
            // GET인 경우 화면은 직접 생성하고 => POST는 시큐리티 사용
            // 127.0.0.1:8080/BOOT1/member/login.do
            // <form th:action="@{/member/loginaction.do}" method="post">
            // <input type="text"  name="userid" />
            http.formLogin()
                .loginPage("/member/login.do")
                .loginProcessingUrl("/member/loginaction.do") //post로 가야될 주소
                .usernameParameter("userid")
                .passwordParameter("userpw")
                .successHandler(new CustomLoginSuccessHandler()) //successHandler => Handler이니까 패키지로만 들어갈 수 있다
                // .defaultSuccessUrl("/home.do") //모든 아이디가 성공하면 home으로
                .permitAll();

            // 로그아웃 => GET불가 , POST로 사용
            http.logout()
            .logoutUrl("/member/logoutaction.do")
            .logoutSuccessHandler(new CustomLogoutSuccessHandler())
            // .logoutSuccessUrl("/home.do") //로그아웃 성공시 권한과 상관없이 home으로
            .invalidateHttpSession(true)
            .clearAuthentication(true)
            .permitAll();

📁 CustomLoginSuccessHandler.java

로그인 성공했을때 동작할 클래스 생성

AuthenticationSuccessHandler 인터페이스를 상속받아
오버라이드 메서드onAuthenticationSuccess를 사용한다

  • CustomDetailsService.java 에서
    UserDetails를 반환할 때 회원의 권한정보를 컬렉션에 담아줬었다
    = 권한을 여러개 담아주기 위해서 Collection<> 형태로 변환
  • 컬렉션에 담겨져있는 권한정보를 다시 문자형태toString로 변환 후 사용
    생성 완료 후 SecurityConfig.java에 CustomLoginSuccessHandler를 넣어준다
    ➡️ successHandler(new CustomLoginSuccessHandler())
public class CustomLoginSuccessHandler implements AuthenticationSuccessHandler{

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
            Authentication authentication) throws IOException, ServletException {

        // 필요한 기능, 권한에 따라서 이동하는 페이지를 다르게 구현
        // 시큐리티는 
        // 컬렉션타입을 문자형태로 변환했다
        String role = authentication.getAuthorities().toArray()[0].toString();
        if(role.equals("CUSTOMER")){
            // 이동하고자 하는 위치 작성
            // request.getContextPath() = /BOOT1
            response.sendRedirect(request.getContextPath() + "/customer/home.do");
        }
        else if(role.equals("SELLER")){
            response.sendRedirect(request.getContextPath() + "/seller/home.do");
        }
        else if(role.equals("ADMIN")){
            response.sendRedirect(request.getContextPath() + "/admin/home.do");
        }
    }
}

📁 CustomLogoutSuccessHandler.java

로그아웃 성공했을때 동작할 클래스 생성

public class CustomLogoutSuccessHandler implements LogoutSuccessHandler {

    @Override
    public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
            throws IOException, ServletException {
        // 로그아웃 수행시 필요한 기능 구현
        response.sendRedirect(request.getContextPath() + "/home.do");
    }
    
}

📌 아이템 이미지 등록

해당하는 아이템 번호의 하위에 이미지가 등록되어야 함

📁 seller/home.html

테이블에 아이템 이미지 버튼 생성
이때 itemno를 같이 넘겨준다 ➡️ 이미지가 등록될 물품번호 파악

<!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>
    <h3>판매자 홈화면</h3>

    <a th:href="@{/seller/insert_item_batch.do}"><button>일괄추가</button></a>
    <hr />
    <br />
    <table border="1">
        <tr>
            <th>물품번호</th>
            <th>물품명</th>
            <th>물품내용</th>
            <th>가격</th>
            <th>수량</th>
            <th>등록일</th>
            <th>버튼</th>
        </tr>
        <tr th:each="obj, idx : ${list}">
            <td th:text="${obj.no}"></td>
            <td th:text="${obj.name}"></td>
            <td th:text="${obj.content}"></td>
            <td th:text="${obj.price}"></td>
            <td th:text="${obj.quantity}"></td>
            <td th:text="${obj.regdate}"></td>
            <td><a th:href="@{/seller/itemimage.do(itemno=${obj.no})}"><button>이미지등록</button></td>
        </tr>

        <th:block th:each="i : ${#numbers.sequence(1,cnt)}">
            <a th:href="@{/seller/home.do(page=${i})}" th:text="${i}"></a>
        </th:block>
    </table>
</body>

</html>

📁 SellerController.java

아이템 이미지 등록페이지 생성 = Get

➡️ ITEMIMAGETBLITEMNO를 외래키로 갖고있다
seller/home.html에서 넘겨준 물품번호를 model에 넣어 return해준다

// 아이템 이미지 등록하기
    @GetMapping(value = "/itemimage.do")
    public String itemImageGET(@RequestParam(name = "itemno") Long itemno, Model model ){
        model.addAttribute("itemno", itemno);

        return "seller/insert_item_image";
    }

📁 insert_item_image.html

enctype="multipart/form-data” ➡️ 파일첨부시 사용
accept="image/*” ➡️ 사용시 첨부때 이미지만 첨부가능

💡 ITEMIMAGETBLITEMNO를 외래키로 갖고있기 때문에 이미지 파일 첨부 후 데이터 전송시 itemno 도 같이 첨부되어야 한다!
반복문에 들어갈 필요는 없고 input type="hidden" 사용하여 같이 보내준다

<!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>
    <a th:href="@{/seller/home.do}">판매자홈으로</a>
    <hr />
    물품이미지등록
    <hr />
    
    <form th:action="@{/seller/insert_itemimage_batch.do}" method="post" enctype="multipart/form-data">
        <input type="hidden" name="itemno" th:value="${itemno}" />
        <th:block th:each="i : ${#numbers.sequence(1,2)}" >
            <input type="file" accept="image/*" name="file" />
            <br />
        </th:block>
        <hr />
        <input type="submit" value="이미지 일괄추가" />
    </form>
    <hr />
    <th:block th:each="obj, idx : ${list}">
        <img th:src="@{/seller/image(no=${obj.no})}" style="width:50px; height:50px" />
    </th:block>
</body>

</html>

📁 ItemImageDTO.java

이미지 등록을 위한 ItemImageDTO 생성

@Getter
@Setter
@ToString
@NoArgsConstructor
public class ItemDTO {
    private Long no;
    private String name;
    private String content;
    private Long price;
    private Long quantity;
    private Date regdate;
    private String seller;
}

📁 ItemImageMapper.java

@Mapper
public interface ItemImageMapper {
    
    // 1개의 이미지 등록
    public int insertImage(ItemImageDTO obj);
...

📁 itemimageMapper.xml

<mapper namespace="com.example.mapper.ItemImageMapper">
    
    <!-- 물품 사진 추가하기 -->
    <insert id="insertImage" parameterType="com.example.dto.ItemImageDTO">
     INSERT INTO ITEMIMAGETBL(NO, ITEMNO, IMAGENAME, IMAGESIZE, IMAGETYPE, IMAGEDATA ,REGDATE)
          VALUES (SEQ_ITEMIMAGE_NO.NEXTVAL, #{itemno}, 
               #{imagename}, #{imagesize}, #{imagetype}, 
               #{imagedata, jdbcType=BLOB}, CURRENT_DATE)
    </insert>
...

📁 SellerController.java

아이템 이미지 등록하기 생성 = Post

// 아이템 이미지 등록하기
    @PostMapping(value = "/insert_itemimage_batch.do")
    public String insertItemImagePOST(
        @RequestParam(name = "itemno") Long itemno,
        @RequestParam(name = "file") MultipartFile[] file
    ) throws IOException {

        // ItemImageDTO 생성
        // List<ItemImageDTO> 생성하여 list로 한번에 전송 
        List<ItemImageDTO> list = new ArrayList<>();
        for(int i=0; i<file.length; i++){
            ItemImageDTO item = new ItemImageDTO();
            item.setItemno(itemno);
            item.setImagetype(file[i].getContentType());
            item.setImagename(file[i].getOriginalFilename());
            item.setImagesize(file[i].getSize());
            item.setImagedata(file[i].getBytes());

            list.add(item);

            // 반복문 종료 후에 list를 전달해서 일괄추가 해야함
            // 반복문 내부에서 1개씩 추가함
            iiMapper.insertImage(item);
        }
        return "redirect:/seller/home.do";
    }

📌 물품 상세페이지에서 이미지 조회

📁 ItemImageMapper.java

💡 이미지 조회 = image src를 반복문으로 여러번 호출하는 개념
이미지 조회는 목록으로 가져오면 되면 안되고 하나씩 꺼내야 한다
List 사용 불가

// 이미지 조회
    // view에서 <img src=""
    public ItemImageDTO selectImageOne(Long no);

    // 이미지 목록 가져오기
    public List<ItemImageDTO> selectImageList(Long itemno);

📁 itemimageMapper.xml

  1. 이미지 url 조회
    ⇒ select에서 바로 타입 변환이 안되기 때문에 Map을 이용하여 타입 변환 후 select에 넣어준다
  2. 이미지 번호 조회
    ⇒ 이미지 url은 1에서 따로 조회 처리됐으니 이미지 번호만 조회해온다

mapper.java에서 리턴타입에 맞춰 꼭 리스트로 리턴해주지 않아도 된다!
ItemImageMapper.javaSellerController.java에서는 selectImageList리턴시 동일하게 List<ItemImageDTO> 형태를 리턴해주고 있다

🤷‍♀️ 왜 ItemImageMapper.java 에서 반환되는 List<ItemImageDTO>와 itemimageMapper.xml의 리턴값 ItemImageDTO는 동일하지 않을까?
👩‍🔧 itemimageMapper.xml selectImageList에서 이미지 조회시 쿼리문을 확인하면 SELECT [I.NO](http://i.no/) FROM ITEMIMAGETBL I WHERE I.ITEMNO=#{itemno}의 결과가 1개 이상인것을 예측할 수있다!
그렇기 떄문에 itemimageMapper.xml은 ItemImageDTO로 반환해 주어도 여러개의 DTO가 반환되는 경우 List<ItemImageDTO> 형태를 가질수 있기 때문에 리턴값은 동일하지 않아도 된다

		<!-- image url 조회 -->
    <resultMap id="retMap1" type="com.example.dto.ItemImageDTO">
        <result property="imagedata" column="IMAGEDATA" jdbcType="BLOB" javaType="[B" />
    </resultMap>
    <select id="selectImageOne" parameterType="ItemImageDTO" resultMap="retMap1">
        SELECT I.* FROM ITEMIMAGETBL I WHERE I.NO=#{no}
    </select>

    <!-- 이미지 번호만 조회 -->
    <select id="selectImageList" parameterType="long" resultType="com.example.dto.ItemImageDTO">
        SELECT I.NO FROM ITEMIMAGETBL I WHERE I.ITEMNO=#{itemno}
    </select>

📁 SellerController.java

// 아이템 이미지 등록페이지 + 기존 등록 이미지 조회하기
    @GetMapping(value = "/itemimage.do")
    public String itemImageGET(@RequestParam(name = "itemno") Long itemno, Model model ){
        
        List<ItemImageDTO> list = iiMapper.selectImageList(itemno);
        System.out.println(list.toString());

        //<img src 사용할 번호들
        model.addAttribute("list", list);
        model.addAttribute("itemno", itemno);

        return "seller/insert_item_image";
    }

📁 insert_item_image.html

반복문 추가하여 기존에 등록된 이미지를 조회해 온다

 <th:block th:each="obj, idx : ${list}">
        <img th:src="@{/seller/image(no=${obj.no})}" style="width:50px; height:50px" />

📌 세션 시간 설정

application.properties

# 세션 시간 설정
server.servlet.session.timeout=13600

📌 물품 상세페이지 이미지 수정/삭제

📁 insert_item_image.html

수정/삭제 버튼 생성

물품번호no와 아이템 이미지 번호itemno도 받아온다

<th:block th:each="obj, idx : ${list}">
        <img th:src="@{/seller/image(no=${obj.no})}" style=" width:50px; height:50px" />

        <form th:action="@{/seller/update_item_image.do}" enctype="multipart/form-data" method="post" style="display:inline-block; border:1px solid slategrey" >
            <input type="file" name="file" />
            <input type="hidden" th:value="${obj.no}" name="no" />
            <button>수정</button>
        </form>

        <form th:action="@{/seller/delete_item_image.do}" method="post" style="display:inline-block">
            <input type="hidden" th:value="${obj.no}" name="no" />
            <input type="hidden" th:value="${itemno}" name="itemno" />
            <button>삭제</button>
        </form>
    </th:block>

🕹️ 이미지 삭제

📁 SellerController.java

삭제 = post
삭제 완료 후 model에 return 값과 전달받았던 값 itemnoinsert_item_image.html로 다시 보낸다
= ➡️ 삭제 완료 후 해당페이지 이동하기 위해

// 아이템 이미지 삭제
    @PostMapping(value = "/delete_item_image.do")
    public String deletePOST(
        @RequestParam(name = "no") Long no, @RequestParam(name = "itemno") Long itemno){
            
        int ret = iiMapper.deleteImageOne(no);
        if(ret>0){
            return "redirect:/seller/itemimage.do?itemno="+itemno;
        }
            return "redirect:/seller/home.do";
        }

📁 ItemImageMapper.java

원래 삭제시 seller 권한 일치 여부도 확인해야한다
삭제는 조건이 까다로워야 한다!

public int deleteImageOne(Long map);

📁 itemimageMapper.xml

<delete id="deleteImageOne" parameterType="Long">
        DELETE FROM ITEMIMAGETBL WHERE NO=#{no}
    </delete>

🕹️ 이미지수정

📁 SellerController.java

수정 = post

@PostMapping(value = "/update_item_image.do")
    public String updatePOST(
        @RequestParam(name = "no") Long no,
        @RequestParam(name = "itemno") Long itemno,
        @RequestParam(name = "file") MultipartFile file) throws IOException{

            ItemImageDTO item = new ItemImageDTO();
            item.setNo(no);
            item.setItemno(itemno);
            item.setImagename(file.getOriginalFilename());
            item.setImagetype(file.getContentType());
            item.setImagesize(file.getSize());
            item.setImagedata(file.getBytes());

            int ret = iiMapper.updateImageOne(item);
            if(ret > 0){
                return "redirect:/seller/itemimage.do?itemno="+itemno;
            }
            return "redirect:/seller/home.do";
        }

📁 ItemImageMapper.java

public int updateImageOne(ItemImageDTO obj);

📁 itemimageMapper.xml

<update id="updateImageOne" parameterType="ItemImageDTO">
        UPDATE ITEMIMAGETBL SET 
        IMAGETYPE=#{imagetype}, 
        IMAGENAME=#{imagename},
        IMAGESIZE=#{imagesize}, 
        IMAGEDATA=#{imagedata, jdbcType=BLOB}
    WHERE NO=#{no}
    </update>

0개의 댓글