<table class="table sorting mt-5" id="categories">
     <thead>
          <tr class="entire">
                <th scope="col"> # </th>
                <th scope="col">제 목</th>
                <th scope="col">수 정</th>
                <th scope="col">삭 제</th>
          </tr>
      </thead>
      <tbody>
                 <!-- th:id="'id_'+${category.id}" ??-->
                <tr th:each="category : ${categories}" th:id="'id_' + ${category.id}" th:class="${category.slug}">
                    <td th:text="${category.sorting}" scope="row"></td>
                    <td th:text="${category.name}"></td>
                    <td><a th:href="@{'/admin/categories/edit/' + ${category.id}}">수정</a></td>
                    <td><a th:if="${category.name != '전체'}" th:href="@{'/admin/categories/delete/'                                             ${category.id}}" class="deleteConfirm">삭제</a>
                    </td>
                </tr>
      </tbody>
</table>
                

해결

두개 같이 적용하는 법

items: 'tr:not(.category, .전체)'

 

 

 

.category.전체  두개의 클래스를 css처리하기

1. cursor: pointer

2. :hover 배경색

적용 안되도록 

table.sorting tr:not(.category,.전체){
    cursor: pointer;
}


table.sorting tr:not(.category,.전체):hover{
    background-color: silver;
}

 

반응형
LIST

수정할때는 id로 DB에 정보 추출하여

model.attribute("category',category); 를 써야 정보 그대로 불러올수있다

 

/ 카테고리 수정
@GetMapping("/edit/{id}")
public String edit(@PathVariable int id, Model model) {

    Category category = categoryRepo.getById(id);
    model.addAttribute("category", category);

    return "/admin/categories/edit";
}
반응형
LIST

https://jqueryui.com/sortable/ 

 

Sortable | jQuery UI

Sortable Reorder elements in a list or grid using the mouse. Enable a group of DOM elements to be sortable. Click on and drag an element to a new spot within the list, and the other items will adjust to fit. By default, sortable items share draggable prope

jqueryui.com

마우스로 순서 변경해주기

 

제이쿼리-UI 링크 footer 에 추가 (제이쿼리 다음)

<script src="https://code.jquery.com/ui/1.12.0/jquery-ui.min.js"></script>

 

<table class="table sorting" id="pages">
  <tr class="home">
    <th>제 목</th>
    <th>슬러그</th>
    <th>수 정</th>
    <th>삭 제</th>
  </tr>
  <tr th:each="page : ${pages}" th:class="${page.slug}" th:id="'id_'+${page.id}"> <!--AdminPageController 의 pages-->
    <td th:text="${page.title}"></td>
    <td th:text="${page.slug}"></td>
    <td><a th:href="@{'/admin/pages/edit/' + ${page.id}}">수정</a></td>
    <td><a th:if="${page.slug != 'home'}" th:href="@{'/admin/pages/delete/' + ${page.id}}" class="deleteConfirm">삭제</a></td> <!--home빼고 삭제, class는 제이쿼리 사용-->
  </tr>
</table>
 

table에 class추가

tr에 class,id추가

 

 

<script>
    $('table#pages').sortable({
        items: 'tr:not(.home)', //클래스 home만 제외하고 sortable
    });
</script>

 

 


제이쿼리 오류!?

 

오류위치가 script안에 sorting을 가르키지만 코드는 문제가 없다..

 

 

 

제이쿼리를 바꿔보자!!

jquery cdnjs 에 들어가서 최신 제이쿼리로 

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js" integrity="sha512-894YE6QWD5I59HgZOGReFYm4dnWc1Qt5NtvYSaNcOP+u1T9qYdvdihz0PPSiiqn/+/3e7Jo4EaG7TubfWGUrMQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>

오 류 해 결.

 

 


그러나

순서를 옮겼는데 새로고침을 하니 바뀐 순서가 원래대로 돌아감

DB에 저장해야 안돌아간다!!

 

 

sorting이 크면 아래로 설정하기.

 

update : 순서가 바뀌었을 때 함수 실행

<script>
    $('table#pages').sortable({
        items: 'tr:not(.home)',  //클래스 home만 제외하고 sortable
        update: function(){     //순서가 바뀌었을때 함수 실행
            let ids = $('table#pages').sortable("serialize"); 
            console.log(ids);
            let url = "/admin/pages/reorder"; 
        }
    });
</script>

 let ids = $('table#pages').sortable("serialize");  이 부분이

 <tr th:id="'id_' + ${page.id}" 를 시리얼라이즈

id_1
id_2
 
 
 
 

serialize 시리얼라이즈?

id를 옮긴 순서대로 시리얼라이즈 해준다

  • console.log(ids) 

이렇게 시리얼라이즈가 됨.

 


제이쿼리 AJAX 추가

$.post('주소','데이터',function(res) {
    //성공시 동작
}

<script>
    $('table#pages').sortable({
        items: 'tr:not(.home)',  //클래스 home만 제외하고 sortable
        update: function(){     //순서가 바뀌었을때 함수 실행
            let ids = $('table#pages').sortable("serialize"); 
            console.log(ids);
            let url = "/admin/pages/reorder"; 
        }
        
        $.post(url,ids,function(data){
    	console.log(data);
		})
    });
</script>
AJAX post로 url주소로 ids를 전송하고 결과를 data로 받기.

 

 

 let url = "/admin/pages/reorder"; 

controller에 reorder로 Post매핑 만들기

//sorting 
//AJAX에서 요청을 한다. 
@PostMapping("/reorder")
public @ResponseBody String reorder(@RequestParam("id[]") int[] id) { //파라미터이름 id[], 정수형 배열

    int count = 1;
    Page page;

    for(int pageId : id) {
        page = pageRepo.getById(pageId); //db에서 id로 page객체 검색
        page.setSorting(count); //sorting 값에 1을 넣고
        pageRepo.save(page); 	//DB에 저장
        count++;			//그 다음은 2
    }

    return "ok";
}

@ResponseBody

view대신 데이터(문자열 "ok")만 가게하기 위해 

 

 

DB의 sorting도 바꿔줌

sorting에 넣을 int count = 1; 설정해주고 count++

입력받은 id배열들을 반복문 for로

아이디로만 찾아 setSorting(count)해주고 1을 넣어줌

마지막으로 save(page) 저장

 

 

DB에 sorting을 다시 가져와야 새로고침할때 안돌아감 그러기 위해

findAll() -> id순으로 가져오기 때문에 다른 메소드이름으로 바꿔야한다!
findAllByOrderBySortingAsc() -> sorting을 오름차순으로 정렬

 

@GetMapping
public String index(Model model) {

    List<Page> pages = pageRepo.findAllByOrderBySortingAsc(); 
    model.addAttribute("pages", pages);

    return "admin/pages/index";
}

 

반응형
LIST

 

[ index.html ]

 

삭제버튼에 

th:href="@{'/admin/pages/delete/' + ${page.id}}"

( 조심! 슬래시 / 안빠뜨리기!)

 

@GetMapping("/delete/{id}")
public String delete(@PathVariable int id, RedirectAttributes attr) {
		
    pageRepo.deleteById(id);
    attr.addFlashAttribute("message", "페이지가 삭제되었습니다.");
    attr.addFlashAttribute("alertClass", "alert-success");

    return "redirect:/admin/pages";
}

id로 삭제한다.  →  deleteById(id) 메서드 사용

redirect로 현재페이지에서 바로 삭제하도록

 

 

 

삭제 message창 뜨게 하려면 바로 삭제되어 페이지 이동없는 index.html에서 삭제 메세지창 추가할 위치에 넣기

<div th:if="${message}" th:text="${message}" th:class="${'alert '+ alertClass}"></div>

 


삭제 팝업창뜨는거 확인하기 -> 제이쿼리로 삭제 확인하기

 

1. 먼저, 삭제버튼에 class="deleteConfirm" 추가하기

2. app.js를 만든다

 

$('a.deleteConfirm').click(function(){
    if(!confirm("페이지 삭제 하시겠습니까?")) return false;
})
  • deleteConfirm클래스가 있는 a태그를 클릭했을때 함수 실행

삭제하시겠습니까?   취소 눌렀을때 true가 되어 삭제 불가.

  • !확인(true) = F
  • !취소(false) = T 

 

 

footer 의 스크립트중 마지막 추가

<script th:src="@{/js/app.js}"></script>

 

 

Home페이지는 삭제 안되도록!

삭제버튼에 

title이 Home이 아닌것만 삭제버튼 나오게 (나머지들만 삭제버튼 생성)

<a th:if="${page.title != 'Home'}">삭제</a>
반응형
LIST

 

th:action="@{/admin/pages/add}" : 태그의 action 속성 값
 
th:href="@{/admin/pages/add}" : 태그의 href 속성을 지정
 

form 태그에 th:href 를 썼다가
Request method 'POST' not supported 에러 뜸.
 
 
 
 
수정버튼을 눌렀을때
<tr th:each="page : ${pages}">
   <td><a th:href="@{'/admin/pages/edit/' + ${page.id}}">수정</a></td>
</tr>
 

id만으로 수정 전 값을 보여줄수있다?

 

 

[edit.html] 

히든으로 id와 sorting 값도 추가한다. (DB에서 못가져오니까)

id와 sorting은 수정하지 않지만 수정시 필요한 값들

<input type="hidden" th:field="*{id}">
<inputtype="hidden" th:field="*{sorting}">

※ 이걸 쓰지 않으면 수정이 아니라 새로운 페이지가 만들어진다.
 

☆  th:field를 쓰면 id,name,value값까지 자동입력 

 

 

 

 

@PostMapping("/add")와 비슷하다.

@PostMapping("/edit")
public String edit(@Valid Page page, BindingResult bindingResult, RedirectAttributes attr) {

    //에러 있으면 다시 에러페이지로
    if(bindingResult.hasErrors()) {
        return "admin/pages/edit";
    }
    
    attr.addFlashAttribute("message", "페이지 수정되었습니다.");
    attr.addFlashAttribute("alertClass", "alert-success");

    //슬러그가 없으면 제목을 소문자로,공백은 "-"로 대체 : 있으면 슬러그를 소문자로,공백을 "-"로 대체
    String slug = (page.getSlug() == "") ? page.getTitle().toLowerCase().replace(" ", "-")
    : page.getSlug().toLowerCase().replace(" ", "-");
    Page sulgExist = pageRepo.findBySlugAndIdNot(slug,page.getId()); //슬러그를 수정안할때를 대비해 같은 슬러그라고 에러 안뜨도록 id도 추가해서 구분하기
    //슬러그를 찾는데 id 로 찾은건 아님!

    if(sulgExist != null) {
        attr.addFlashAttribute("message", "이미 같은 슬러그가 존재합니다.");
        attr.addFlashAttribute("alertClass", "alert-danger");
        attr.addFlashAttribute("page", page); //또안됨 안지워지고 다시 불러오는 @@안됨 get매핑에서 @ModelAttribute써야 나옴??
    }else {
        page.setSlug(slug); //수정된 슬러그 저장
        //page.setSorting(100); // 기본 0으로 저장이 됨 수정할땐 필요없음

        pageRepo.save(page);
    }
    return "redirect:/admin/pages/edit/" + page.getId(); //post-redirect-get
}

 

 

findBySlugAndIdNot 가 내가 지은 메소드 이름이 아니고 원래 있는 이름.. ? = where slug = 슬러그 and id != 아이디

(slug,page.getId()) 두 변수를 왜 쓰느냐?

1. slug를 수정 안해도 id로 구분한다!

2. slug를 찾는데 현재id를 제외하고 다른 id로 있는 동일한 slug가 있는지 찾는다! 

Page sulgExist = pageRepo.findBySlugAndIdNot(slug,page.getId());

 

findBySlugAndIdNot 메소드 이름안에 And, Not 키워드로 메소드이름을 읽어야함

 

JPA 메소드 이름 안에서 지원되는 키워드

 

반응형
LIST

Model 객체는 Controller 에서 생성된 데이터를 담아 View 로 전달할 때 사용하는 객체이다.

 

 

[get 매핑]

@GetMapping("/add")
public String add(Model model) { 

  model.addAttribute("page", new Page() );

  return "admin/pages/add";
}
<h2> Test Method : ${page} </h2>

 

 

그리고 

@ModelAttribute 어노테이션을 써서 간략해질수 있다고 했다

 

@GetMapping("/add")
public String add(@ModelAttribute Page page) { 
   return "admin/pages/add";
}

 

 

근데!! get매핑에서 Model 객체를 썼을 때

 

 

@PostMapping("/add")
public String add(@Valid Page page, BindingResult bindingResult, RedirectAttributes attr, Model model) {

        ~~

        attr.addFlashAttribute("page", page); 
}

 

 

문제발생!

페이지의 슬러그가 존재하면 안지워고 문자그대로 남게 하려면

attr.addFlashAttribute("page", page); 

이걸 쓰는데 

안불러진다 

왜??

 

 

 

 

나의 추측.

post매핑에서 return "redirect:/admin/pages/add";  리다이렉트를 하기때문! (post-get순으로 리다이렉트)
입력한 정보를 다시 get매핑으로 리다이렉트해서 page를 받고 다시 보내지기 때문 정보 불러올 수 있다

 

 

 

 

결론 

 

Get매핑에서 @ModelAttribute 을 써야  쓴 문자가 그대로 불러와진다 

 

[get매핑]

 

public String add(Model model) { 
   model.addAttribute("page", new Page() );
   return "admin/pages/add";
}

 

이렇게는 입력했던 정보를 다시 불러 올 수 없음.  page를 받는게 없기때문!

 

 

 

 

 

반응형
LIST

'Spring boot | 쇼핑몰 만들기 | 어글리 마켓 > 홈페이지 만들기 | 고객,관리자' 카테고리의 다른 글

페이지 삭제하기  (0) 2022.05.01
페이지 수정하기  (0) 2022.04.30
페이지 추가  (0) 2022.04.30
페이지 만들기  (0) 2022.04.30
부트스트랩  (0) 2022.04.30

+ Recent posts