어제 Spring으로 CRUD 만들고 시큐리티
적용하고 뭘 만들지....하다가
사람들이 Rest를 항상 이야기해서 Rest에
대해서 공부해봤습니다.
그 결과 오늘 하루 종일 해서 게시물 CRUD까지는 구현이 가능하게 돼서
이렇게 기록도 남기고 포스팅을 해봅니다.
먼저 기본 환경은
Spring(legacy) | Java 8 | Oracle | Mybatis | Tomcat 9.0
ojdbc6.jar
이렇게입니다.
먼저 pom.xml
<properties>
<java-version>1.8</java-version>
<org.springframework-version>5.0.8.RELEASE</org.springframework-version>
<org.aspectj-version>1.6.10</org.aspectj-version>
<org.slf4j-version>1.6.6</org.slf4j-version>
<spring.security.version>4.1.3.RELEASE</spring.security.version>
</properties>
<dependencies>
<!-- Spring -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${org.springframework-version}</version>
<exclusions>
<!-- Exclude Commons Logging in favor of SLF4j -->
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${org.springframework-version}</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${org.springframework-version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<version>${spring.security.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>${spring.security.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>${spring.security.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-taglibs</artifactId>
<version>${spring.security.version}</version>
</dependency>
<!-- AspectJ -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>${org.aspectj-version}</version>
</dependency>
<!-- Logging -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${org.slf4j-version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>${org.slf4j-version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${org.slf4j-version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.15</version>
<exclusions>
<exclusion>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
</exclusion>
<exclusion>
<groupId>javax.jms</groupId>
<artifactId>jms</artifactId>
</exclusion>
<exclusion>
<groupId>com.sun.jdmk</groupId>
<artifactId>jmxtools</artifactId>
</exclusion>
<exclusion>
<groupId>com.sun.jmx</groupId>
<artifactId>jmxri</artifactId>
</exclusion>
</exclusions>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.bgee.log4jdbc-log4j2</groupId>
<artifactId>log4jdbc-log4j2-jdbc4</artifactId>
<version>1.16</version>
</dependency>
<!-- @Inject -->
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
<!-- Test -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.7</version>
<scope>test</scope>
</dependency>
<!-- Servlet -->
<!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.servlet.jsp/javax.servlet.jsp-api -->
<dependency>
<groupId>javax.servlet.jsp</groupId>
<artifactId>javax.servlet.jsp-api</artifactId>
<version>2.3.3</version>
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/javax.servlet/jstl -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!-- lombok -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${org.springframework-version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.2</version>
<scope>provided</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<!-- mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.6</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring -->
<!-- spring과 연결 -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.6</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.12.1</version>
</dependency>
<dependency><!-- jackson -->
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>1.4.2</version>
</dependency>
여기에서 mybatis나 기본 설정은 모두 되어있을 거라고 생각하고
중요한 거는 맨 밑의 2개
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.12.1</version>
</dependency>
<dependency><!-- jackson -->
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>1.4.2</version>
</dependency>
이 부분 입니다.
Rest에서는 xml이나 json 형식을 읽어오는데
난 그냥 ajax를 위해서 가져온 기본 설정이 Rest에서도 사용되는 것이다...
참고로 이 부분들이 없으면 오류가 계속 난다(경험....)
그다음 sql문
create table rest_board(
bid number not null,
btitle varchar2(100) not null,
bcontent varchar2(2000) not null,
bwriter varchar2(100) not null,
PRIMARY KEY(bid)
);
create sequence rboa_seq start with 1 INCREMENT BY 1 NOCYClE NOCACHE;
commit;
insert into rest_board
values(rboa_seq.nextval,'테스트제목!','테스트 내용!!','admin');
insert into rest_board
values(rboa_seq.nextval,'테스트제목2','테스트 내용2!!','admin');
insert into rest_board
values(rboa_seq.nextval,'테스트제목3','테스트 내용3!!','admin');
insert into rest_board
values(rboa_seq.nextval,'테스트제목4','테스트 내용4!!','admin');
insert into rest_board
values(rboa_seq.nextval,'테스트제목5','테스트 내용5!!','admin');
commit;
select * from rest_board;
아직 회원 기능까지는 못해봐서
게시판에서 필요로 하는 최소한의 기능만 설정해뒀다.
boardmapper.XML
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="board">
<insert id="writeboard" parameterType="kr.co.korea.beans.BoardBean">
insert into rest_board(bid,btitle,bcontent,bwriter)
values(rboa_seq.nextval,#{btitle},#{bcontent},#{bwriter})
</insert>
<select id="readboard" parameterType="Integer" resultType="kr.co.korea.beans.BoardBean">
select bid,btitle,bcontent,bwriter
from rest_board
where bid=#{bid}
</select>
<select id="getboardlist" resultType="kr.co.korea.beans.BoardBean">
select bid,btitle,bcontent,bwriter
from rest_board
</select>
<update id="updateboard" parameterType="kr.co.korea.beans.BoardBean">
update rest_board
set bcontent=#{bcontent},btitle=#{btitle}
where bid=#{bid}
</update>
<delete id="deletebaord" parameterType="Integer">
delete from rest_board
where bid=#{bid}
</delete>
</mapper>
mapper는 기본적인 sql문으로 조합
그다음 BoardBean이다.
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
@Getter
@Setter
@ToString
public class BoardBean {
private int bid;
private String btitle;
private String bcontent;
private String bwriter;
}
이번에 하면서 lombok을 사용했는데
진짜.... bean이 너무 깔끔하게 됐다.
보통은 @Data 하나만으로 해결한다고는 하는데
아직 공부를 하는 중이라 3개만 정의했다.
BoardDao
@Repository
public class BoardDao {
@Autowired
private SqlSessionTemplate sqltemp;
public void writeboard(BoardBean boardbean) {
sqltemp.insert("board.writeboard",boardbean);
}
public BoardBean readboard(int bid) {
return sqltemp.selectOne("board.readboard",bid);
}
public List<BoardBean> getboardlist(){
return sqltemp.selectList("board.getboardlist");
}
public void updateBoard(BoardBean boardbean) {
sqltemp.update("board.updateboard",boardbean);
}
public void deleteBoard(int bid) {
sqltemp.delete("board.deletebaord",bid);
}
}
@Service
public class BoardService {
@Autowired
private BoardDao boarddao;
public void writeboard(BoardBean boardbean,String username) {
boardbean.setBwriter(username);
boarddao.writeboard(boardbean);
}
public BoardBean readboard(int bid) {
return boarddao.readboard(bid);
}
public List<BoardBean> getboardlist(){
return boarddao.getboardlist();
}
public void updateBoard(BoardBean boardbean) {
boarddao.updateBoard(boardbean);
}
public void deleteBoard(int bid) {
boarddao.deleteBoard(bid);
}
}
Dao와 Service는 기존 CRUD와 큰 차이가 없다.
그리고 중요한 마지막 Controller
@RestController
@RequestMapping("/board")
public class BoardController {
private static final Logger logger = LoggerFactory.getLogger(BoardController.class);
@Autowired
private BoardService boardservice;
@GetMapping("")
public List<BoardBean> list() {
logger.info("boardlist");
List<BoardBean> list = boardservice.getboardlist();
return list;
}
@GetMapping("/{bid}")
public BoardBean read(@PathVariable int bid) {
logger.info("boardread");
BoardBean boardbean = boardservice.readboard(bid);
return boardbean;
}
@PostMapping("")
public void write(@RequestBody BoardBean boardbean) {
logger.info("write");
String username="admin";
boardservice.writeboard(boardbean,username);
}
@PutMapping("/{bid}")
public void updateok(@RequestBody BoardBean boardbean,@PathVariable int bid) {
logger.info("updateok");
boardbean.setBid(bid);
boardservice.updateBoard(boardbean);
}
@DeleteMapping("/{bid}")
public void delete(@PathVariable int bid) {
logger.info("delete");
boardservice.deleteBoard(bid);
}
}
먼저 기존의 Controller와의 차이는
RestController이다.
전에 ajax를 이용한 댓글 부분에서 사용했는데
이게 Rest에서도 json, xml 값을 받으니까
이렇게 정의해주면 된다.
그리고 각각 정의되어있는 어노테이션이 다른데
눈에 익숙한 것도 있고 안 익숙한 것도 있다.
@GetMapping | select할 경우 사용(list,상세보기의 경우) |
@PostMapping | insert(글 작성,회원 가입) |
@PutMapping | update(전부 수정) |
@PatchMapping | update(일부 수정) |
@DeleteMapping | delete(삭제) |
여기서 본인이 사용할 부분을 골라서 사용하면 된다.
그런데 여기서 mapping의 value를 보면 자연스럽게 의문이 생긴다
우리가 흔히 알고 있던 것에서는
<c:url value="/board/update? bid=${bid}"/>이런 식으로
작성을 해서 mapping에서도 /update를 넣어주고
읽는 그런 방식을 했다.
그런데 Rest에서는 방식이 다르다.
기본적으로 get, post, put, delete로 각 구분이 가능하다는 점.
그리고 누가 봐도 추측이 가능해야 하다는 것이다.
예를 들어 내가 짠 Controller에서 본다면
http://localhost:8077/board
를 본다면 아마 '아 특정 게시판을 보는 거구나'할 것이고
http://localhost:8077/board/1
'특정 게시판의 특정 게시물 즉 상세보기구나' 할 것이다.
(혼자서 작성하면서 이해한 거라서 틀릴 수 있습니다...)
이렇게 작성을 다 하면 이제 확인을 해봐야 하는데
먼저 Spring legacy이므로 톰캣을 먼저 실행시켜준다.
그 후 이 클립에서 Run As가 아닌
chrome.google.com/webstore/detail/postman/fhbjgbiflinjbdggehcddcbncdddomop?hl=ko
postman을 설치해줍니다.
이것은 간단하게 자신이 짠 코드가 정확히 작동을 해주는지 체크? 해주는 툴이다.
그리고 실행을 시킨 후에
확인을 해보면
1. get 전체 보기
2. get 상세 보기
3.Post(insert)
여기서는 insert이므로 확인을 먼저 해야 합니다.
post 체크
url 체크
body체크
raw 체크
json체크 -> 기본으로 text가 되어있는데 Rest는 json이나 xml형식의 데이터만 이라는 것
text 하면 415 mediatype 오류 발생(경험....)
그리고 마지막에 send를 클릭해줍니다.
그리고 get으로 확인합니다.
참고로 bid는 sequence로 주고 있고
bwriter는 controller에서 임의로 지정했습니다.
4.put(update)
여기서는 자신이 수정할 게시물의 번호 bid를 정해주고
바꿀 내용을 작성해준 뒤 send를 클릭합니다.
5.Delete(delete)
2번 게시물을 삭제해주면
이와 같이 2번 게시물이 삭제된 것을 알 수 있습니다.
이렇게 하면 Spring으로
Rest Crud 구현이 가능합니다.
이제 이것을 view로 뿌리는 방법을 공부하고 다시 포스팅하겠습니다!
코드
'spring > 게시판' 카테고리의 다른 글
스프링 게시판 만들기 좋아요(2) (0) | 2021.04.24 |
---|---|
스프링 게시판 좋아요 버튼 (0) | 2021.04.24 |
스프링 시큐리티 예제 (0) | 2021.04.07 |
스프링 이미지 업로드 (0) | 2021.03.11 |
스프링 selectKey (0) | 2021.03.02 |