현재 설정값
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();
로그인 성공했을때 동작할 클래스 생성
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");
}
}
}
로그아웃 성공했을때 동작할 클래스 생성
public class CustomLogoutSuccessHandler implements LogoutSuccessHandler {
@Override
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
throws IOException, ServletException {
// 로그아웃 수행시 필요한 기능 구현
response.sendRedirect(request.getContextPath() + "/home.do");
}
}
해당하는 아이템 번호의 하위에 이미지가 등록되어야 함
테이블에 아이템 이미지 버튼 생성
이때 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>
아이템 이미지 등록페이지 생성 = Get
➡️ ITEMIMAGETBL
은 ITEMNO
를 외래키로 갖고있다
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";
}
enctype="multipart/form-data”
➡️ 파일첨부시 사용
accept="image/*”
➡️ 사용시 첨부때 이미지만 첨부가능
💡
ITEMIMAGETBL
은ITEMNO
를 외래키로 갖고있기 때문에 이미지 파일 첨부 후 데이터 전송시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 생성
@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;
}
@Mapper
public interface ItemImageMapper {
// 1개의 이미지 등록
public int insertImage(ItemImageDTO obj);
...
<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>
...
아이템 이미지 등록하기 생성 = 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";
}
💡 이미지 조회 =
image src
를 반복문으로 여러번 호출하는 개념
이미지 조회는 목록으로 가져오면 되면 안되고 하나씩 꺼내야 한다
⇒List
사용 불가
// 이미지 조회
// view에서 <img src=""
public ItemImageDTO selectImageOne(Long no);
// 이미지 목록 가져오기
public List<ItemImageDTO> selectImageList(Long itemno);
mapper.java에서 리턴타입에 맞춰 꼭 리스트로 리턴해주지 않아도 된다!
⇒ItemImageMapper.java
와SellerController.java
에서는selectImageList
리턴시 동일하게List<ItemImageDTO>
형태를 리턴해주고 있다
🤷♀️ 왜 ItemImageMapper.java 에서 반환되는
List<ItemImageDTO>
와 itemimageMapper.xml의 리턴값ItemImageDTO
는 동일하지 않을까?
👩🔧 itemimageMapper.xmlselectImageList
에서 이미지 조회시 쿼리문을 확인하면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>
// 아이템 이미지 등록페이지 + 기존 등록 이미지 조회하기
@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";
}
반복문 추가하여 기존에 등록된 이미지를 조회해 온다
<th:block th:each="obj, idx : ${list}">
<img th:src="@{/seller/image(no=${obj.no})}" style="width:50px; height:50px" />
# 세션 시간 설정
server.servlet.session.timeout=13600
수정/삭제 버튼 생성
물품번호
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>
삭제 =
post
삭제 완료 후model
에 return 값과 전달받았던 값itemno
를insert_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";
}
원래 삭제시 seller 권한 일치 여부도 확인해야한다
삭제는 조건이 까다로워야 한다!
public int deleteImageOne(Long map);
<delete id="deleteImageOne" parameterType="Long">
DELETE FROM ITEMIMAGETBL WHERE NO=#{no}
</delete>
수정 =
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";
}
public int updateImageOne(ItemImageDTO obj);
<update id="updateImageOne" parameterType="ItemImageDTO">
UPDATE ITEMIMAGETBL SET
IMAGETYPE=#{imagetype},
IMAGENAME=#{imagename},
IMAGESIZE=#{imagesize},
IMAGEDATA=#{imagedata, jdbcType=BLOB}
WHERE NO=#{no}
</update>