스프링 부트 기초 - 7(스프링 시큐리티, 게시글 작성,조회)

3 minute read

스프링 시큐리티 로그인 방법

@Override
	protected void configure(HttpSecurity http) throws Exception {
		http
			.csrf().disable() // csrf 토큰 비활성화(테스트시 걸우두는게 좋음)
			.authorizeRequests()
				.antMatchers("/", "/auth/**", "/js/**", "/css/**", "/image/**")
				.permitAll()
				.anyRequest()
				.authenticated()
			.and()
				.formLogin()
				.loginPage("/auth/loginForm")
				.loginProcessingUrl("/auth/loginProc") // 스프링 시큐리티가 해당 주소로 요청오는 로그인을 가로챈다. 대신 로그인 해준다.
				.defaultSuccessUrl("/");	// 정상적으로 로그인이 되면 여기로 이동
	}

anyMathcers에 등록되지 않는 url은 /auth/loginForm으로 다 이동

게시글 작성

▶ Board

@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Entity
public class Board {

	@Id	// primary key
	@GeneratedValue(strategy = GenerationType.IDENTITY) // auto_increment
	private int id;

	@Column(nullable = false, length = 100)
	private String title;

	@Lob // 대용량 데이터
	private String content;	// 썸머노트 라이브러리 사용

	private int count; // 조회수

	@ManyToOne	// Many = Board, User = One	-> 한명의 User는 여러개의 Board를 쓸수 있다.
	@JoinColumn(name ="userId")
	private User user; // DB는 오브젝트를 저장할 수 없다. FK, 자바는 오브젝트를 저장할 수 있다.

	@OneToMany(mappedBy = "board", fetch = FetchType.EAGER)
	private List<Reply> reply;

	@CreationTimestamp
	private Timestamp createDate;
}


▶ BoardApiController

@RestController
public class BoardApiController {

	@Autowired
	private BoardService boardService;

	@ResponseBody
	@PostMapping(value = "/api/board")
	public ResponseDto<Integer> save(@RequestBody Board board, @AuthenticationPrincipal PrincipalDetail principal) {// title, content
		boardService.글쓰기(board, principal.getUser());	// principal.getUser()는 현재 세션의 아이디를 의미
		return new ResponseDto<Integer>(HttpStatus.OK.value(),1);
	}
}

saveForm에서 작성된 내용들이 Board로 들어오게 된다. save의 파라미터로 쓰인@AuthenticationPrincipal PrincipalDetail principal는 현재 로그인 되어있는 세션의 아이디를 얻기 위해서 사용 되었다.


▶ BoardService

@Service
public class BoardService {

	@Autowired
	private BoardRepository boardRepository;

	@Transactional
	public void 글쓰기(Board board, User user) {
		board.setCount(0);
		board.setUser(user);
		boardRepository.save(board);
	}

	public List<Board> 글목록() {
		return boardRepository.findAll();	// findAll로 모든 글 가져오기
	}

}

게시글의 count와 user는 직접 설정해준다. 그후 boardRepository.save를 통해 저장


게시글 조회

▶ BoardController

@Controller
public class BoardController {

	@Autowired
	private BoardService boardService;

	@GetMapping(value = {"", "/"})
	public String index(Model model) {	// 세션 접근
		model.addAttribute("boards",boardService.글목록());
		return "index";
	}

	@GetMapping(value = "/board/saveForm")
	public String saveForm() {	// 세션 접근
		return "board/saveForm";
	}

}

페이지를 방문하게 되면 Model을 index로 전달한다.


▶ BoardService

// 스프링이 컴포넌트 스캔을 통해서 Bean에 등록을 해줌. IoC를 해준다.
@Service
public class BoardService {

	public List<Board> 글목록() {
		return boardRepository.findAll();	// findAll로 모든 글 가져오기
	}

}

findAll을 통해 db에 있는 전체 목록을 얻어온다.


▶ index.jsp

<!-- 메인 -->
<div class="container">
 <c:forEach var="board" items="${boards}">
  <div class="card mt-3">
    <div class="card-body">
      <h5 class="card-title">${board.title}</h5>
      <p class="card-text">
        <small class="text-muted"><a href="#" class="btn btn-primary">상세보기</a></small>
      </p>
    </div>
  </div>
 </c:forEach>
</div>

그 후 Model을 통해 가져온 boards를 jstl을 활용하여 보여준다.


게시글 조회(페이지네이션)

▶ BoardController

@Controller
public class BoardController {

	@Autowired
	private BoardService boardService;

	@GetMapping(value = {"", "/"})
	public String index(Model model, @PageableDefault(size = 3, sort = "id", direction = Sort.Direction.DESC) Pageable pageable) {	// 세션 접근
		model.addAttribute("boards",boardService.글목록(pageable));
		return "index";
	}
}

@PageableDefault를 활용하여 스프링에서 제공하는 페이지네이션 사용


▶ BoardService

// 스프링이 컴포넌트 스캔을 통해서 Bean에 등록을 해줌. IoC를 해준다.
@Service
public class BoardService {

// 전체 글 조회는 List 타입인데 pageable을 적용하면 return 타입은 Page 타입으로 변경된다
	public Page<Board> 글목록(Pageable pageable) {
		return boardRepository.findAll(pageable);	// findAll로 모든 글 가져오기
	}

}

@PageableDefault에서 정해준 갯수대로 데이터가 뽑힘


▶ index.jsp

<!-- 메인 -->
  <div class="container">
    <c:forEach var="board" items="${boards.content}">
      <div class="card mt-3">
        <div class="card-body">
          <h5 class="card-title">${board.title}</h5>
          <p class="card-text">
            <small class="text-muted"><a href="#" class="btn btn-primary">상세보기</a></small>
          </p>
        </div>
      </div>
    </c:forEach>

    <!-- 페이지네이션 -->
    <nav aria-label="Page navigation example ">
      <ul class="pagination justify-content-center mt-3">
        <c:choose>
          <c:when test="${boards.first}">
            <li class="page-item disabled"><a class="page-link" href="?page=${boards.number-1}">Previous</a></li>
          </c:when>
          <c:otherwise>
            <li class="page-item"><a class="page-link" href="?page=${boards.number-1}">Previous</a></li>
          </c:otherwise>
        </c:choose>
         <c:choose>
          <c:when test="${boards.last}">
            <li class="page-item disabled"><a class="page-link" href="?page=${boards.number+1}">Next</a></li>
          </c:when>
          <c:otherwise>
            <li class="page-item"><a class="page-link" href="?page=${boards.number+1}">Next</a></li>
          </c:otherwise>
        </c:choose>
      </ul>
    </nav>
  </div>

가장 중요한 것은 forEach문의 items 부분이 ${boards}에서 ${boards.content}로 바뀌었다 → 즉 content를 해야 조회가 가능하다

스프링 페이지네이션의 특징인 first와 last 부분은 페이지네이션이 작동이 안되도록 부트스트랩에서 제공되는 disabled 사용


DeleteMapping 오류

“request method 'delete' not supported” 오류 발생

▶ application.yml

spring:
  mvc:
    view:
      prefix: /WEB-INF/views/ # 파일명 앞에 붙어줌
      suffix: .jsp # 파일명 뒤에 붙여줌
    hiddenmethod:
      filter:
        enabled: true
  • spring.mvc.hiddenmethod.filter.enabled = true 를 추가

📑 출처

Categories:

Updated:

Leave a comment