스프링 부트 기초 - 7(스프링 시큐리티, 게시글 작성,조회)
스프링 시큐리티 로그인 방법
@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 를 추가
Leave a comment