스프링수업 7일차

한 일

RESTful 웹 프로젝트

  • start spring을 통해 프로젝트 생성하기
  • GET 유저 조회하기
  • POST 새 유저 생성하기
  • PUT 유저정보 업데이트하기
  • DELETE 유저 삭제하기

pma 프로젝트에 rest api적용하기 -1-

  • GET으로 직원 검색하기
  • POST로 새 직원 입력하기

RESTful 웹 프로젝트

start spring을 통해 프로젝트 생성하기

https://start.spring.io/
위 링크를 통해 프로젝트 생성.



이후 생성하기 진행 > 생성된 압축파일을 워크스페이스로 옮겨 압축풀기
프로젝트 파일 불러오기로 열기


실행 시 출력되는 페이지.


spring-boot-devtools 추가. 빠른 사용에 도움을 줌.


GET 유저 조회하기


새 클래스 생성

- UserController -

@RestController
@RequestMapping("/users")	// http://localhost:8080/users
public class UserController {

	@GetMapping
	public String getUser() {
		return "유저 리스트 리턴";
	}
	@PostMapping
	public String getCreaterUser() {
		return "새 유저를 생성";
	}
	@PutMapping
	public String getUpdateUser() {
		return "유저 업데이트";
	}
	@DeleteMapping
	public String geDeletetUser() {
		return "유저 삭제";
	}
}

postman에 http://localhost:8080/users 로 접속해 결과확인

GET


POST


PUT


DELETE

@PathVariable으로 path변수 사용하기

- UserController -
getUser, getUserList 로수정 (문자열 기준)

@GetMapping
public String getUserList() {
	return "유저 리스트 리턴";
}
@GetMapping(path = "/{userId}")
public String getUser(@PathVariable("userId") String userId) {
	return "유저 리스트 중 하나 " + userId;
}

id를 숫자로 받을 경우 아래처럼 수정

@GetMapping(path = "/{userId}")
public String getUser(@PathVariable("userId") int userId) {
	return "유저 리스트 중 하나 " + userId;
}


http://localhost:8080/users/0829kuj 의 결과.

쿼리 스트링으로 입력하기

유저의 수가 많을때 일일히 request방식으로 받아오면 비효율적임.
최소page와 최대limit을 쿼리스트링으로 주소에 추가하여 요청.

- UserController -

@GetMapping
public String getUserList(@RequestParam("page") int page, @RequestParam("limit") int limit) {
	return "유저 리스트 리턴 페이지: "+ page + ", limit : " + limit;
}

http://localhost:8080/users?page=1&limit=10

정상응답.

parameter없이 http://localhost:8080/users 로 요청 시 에러발생.
defaultValue(기본값)를 설정하여 에러를 방지.
- UserController -

// 효율적으로 DB를 사용하기 위해 페이지 수와 한 페이지 당 가져올 데이터수를 지정
@GetMapping
public String getUserList(@RequestParam(value= "page", defaultValue = "1") int page, 
						@RequestParam(value = "limit", defaultValue = "50") int limit,
						@RequestParam(value = "sort", defaultValue = "desc", required = false) String sort) {
	return "유저 리스트 리턴 페이지: "+ page + ", limit : " + limit + ", 정렬 : " + sort;
}

sort의 required = false 는 이 속성이 없어도 에러가 발생하지 않도록하는 설정.
defaultValue값을 설정해주지 않았다면 if (sort == null) sort = "DESC"; 를 넣어 기본값을 따로 작성해줘야하지만 여기서는 넣어줬으니 필요없음.

http://localhost:8080/users

수정 전 요청시 에러발생

defaultValue 추가 후 접근 시 에러발생x

java 객체로 리턴받기


새 클래스 생성

- UserRest클래스 -

public class UserRest {
	private String name;
	private String email;
	private String userId;
    // get/set 자동생성
}

- UserController -

@GetMapping(path = "/{userId}")
public UserRest getUser(@PathVariable("userId") String id) {
	// java 객체 유저를 리턴
	UserRest returnUser = new UserRest();
	returnUser.setName("홍");
	returnUser.setUserId(id);
	returnUser.setEmail("[email protected]");
	// 객체로 리턴 시 RestController에서 json으로 리턴
	return returnUser;
}


http://localhost:8080/users/ 뒤에 id를 입력 후 요청하면 입력된 홍길동의 정보가 json으로 리턴됨.
=> 자바객체로 리턴 시 자동으로 json타입으로 response됨.

xml로 리턴받기

xml과 json

링크 에서 2.13.2버전 사용

- pom.xml -
spring이 자동관리하도록 version삭제 > pom.xml에 추가 > 메이븐 업데이트

<dependency>
    <groupId>com.fasterxml.jackson.dataformat</groupId>
    <artifactId>jackson-dataformat-xml</artifactId>
</dependency>

- UserController -

@GetMapping(path = "/{userId}", produces = {MediaType.APPLICATION_JSON_VALUE,
											MediaType.APPLICATION_XML_VALUE})
public UserRest getUser(@PathVariable("userId") String id) {
	// java 객체 유저를 리턴
	UserRest returnUser = new UserRest();
	returnUser.setName("홍");
	returnUser.setUserId(id);
	returnUser.setEmail("[email protected]");
	// 객체로 리턴 시 RestController에서 json으로 리턴
	return returnUser;
}

여기서 mediaType은 org.springframework.http.MediaType이니 import시 주의.
produces속성을 추가하여 미디어타입을 지정.
xml과 json을 모두 리턴할 수 있도록 해줌.

재시작 후 확인.


Header의 Accept 설정을 application/xml 로 바꾼 후 재확인.


xml로 리턴됨을 확인가능.

HTTP 상태코드

http상태코드를 함께 리턴하기.
http상태코드: 200번대 - 정상응답, 400번대 - 요청오류, 500번대 - 서버오류

http상태코드 참고

- UserController -

@GetMapping(path = "/{userId}", produces = {MediaType.APPLICATION_JSON_VALUE,
											MediaType.APPLICATION_XML_VALUE})
public ResponseEntity<UserRest> getUser(@PathVariable("userId") String id) {
	// java 객체 유저를 리턴
	UserRest returnUser = new UserRest();
	returnUser.setName("홍");
	returnUser.setUserId(id);
	returnUser.setEmail("[email protected]");
	// 객체로 리턴 시 RestController에서 json으로 리턴
	return new ResponseEntity<UserRest>(returnUser, HttpStatus.BAD_REQUEST);
}
@GetMapping("/bad")
public ResponseEntity<String> badRequest() {
	return new ResponseEntity<String>("잘못된 요청", HttpStatus.BAD_REQUEST);
}

BAD_REQUEST를 OK로 바꿨을때도 확인해보기




POST 새 유저 생성하기


새 클래스 생성

- UserRequest -

public class UserRequest {
	private String name;
	private String email;
	private String password;
	//getset 자동생성
}

- UserController -

@PostMapping
public String getCreaterUser(@RequestBody UserRequest user) {
	return "새 유저를 생성";
}

@RequestBody: 실제 요청시의 데이터


post로 데이터가 전달되는지 확인

- UserController -

@PostMapping
public ResponseEntity<UserRest> getCreaterUser(@RequestBody UserRequest user) {
	UserRest returnUser = new UserRest();
	returnUser.setName(user.getName());
	returnUser.setEmail(user.getEmail());
	
	return new ResponseEntity<UserRest>(returnUser, HttpStatus.CREATED);
}


요청성공 시 화면.

데이터 검증 Validating Request Body

POST로 입력받은 값 검증하기

라이브러리 다운 pom.xml에 추가.
이전과 마찬가지로 spring이 자동관리하도록 version태그는 삭제.

- UserController -

@PostMapping
public ResponseEntity<UserRest> getCreaterUser(@Valid @RequestBody UserRequest user) {
	UserRest returnUser = new UserRest();
	returnUser.setName(user.getName());
	returnUser.setEmail(user.getEmail());
	
	return new ResponseEntity<UserRest>(returnUser, HttpStatus.CREATED);
}

@Valid로 userRequest로 들어오는 user의 유효성을 검사

- UserRequest클래스 -

@NotBlank(message="이름을 입력해주세요")
private String name;

@NotBlank(message="이메일을 입력해주세요")
@Email
private String email;

@NotNull(message = "패스워드를 입력해주세요")
@Size(min = 4, max = 10, message = "패스워드의 길이는 4 ~ 10 사이입니다")
private String password;

어노테이션으로 유효성 설정

재시작 후 확인. (maven을 수동으로 추가했을땐 재시작 후 확인해야 변경사항이 적용됨)


유효성에 어긋나는 요청 시 에러와 함께 설정한 메시지가 출력됨.
정상요청의 경우 상단의 유효성 적용 전 결과와 동일하므로 생략.

userId 자동생성해서 저장하기

우선 DB를 사용하지 않고 리스트로 생성하여 저장.

- UserController -

@PostMapping
public ResponseEntity<UserRest> getCreaterUser(@Valid @RequestBody UserRequest user) {
	UserRest returnUser = new UserRest();
	returnUser.setName(user.getName());
	returnUser.setEmail(user.getEmail());
	String userId = UUID.randomUUID().toString();	// 랜덤한 고유id를 만듦
	returnUser.setUserId(userId);
	
	if (users == null) users = new HashMap<>();	// 싱클톤 패턴. 선언된 map <문자열, UserRest>가 없으면 새로생성
	users.put(userId, returnUser);		// map이므로 (유저id, 유저객체) 를 한쌍으로 입력
	
	return new ResponseEntity<UserRest>(returnUser, HttpStatus.CREATED);
}


post를 통해 새 유저를 생성 시 랜덤하게 생성된 userId가 함께 저장됨.

- UserController -
userId로 유저를 찾아 리턴, 없을 시 없음을 알리도록 수정.

@GetMapping(path = "/{userId}", produces = {MediaType.APPLICATION_JSON_VALUE,
											MediaType.APPLICATION_XML_VALUE})
public ResponseEntity<UserRest> getUser(@PathVariable("userId") String id) {
	// java 객체 유저를 리턴
	if (users.containsKey(id)) {
		return new ResponseEntity<UserRest>(users.get(id), HttpStatus.OK);	
	} else {	// userId가 없음을 알림
		return new ResponseEntity<UserRest>(HttpStatus.NO_CONTENT);
	}


앞서 만든 유저의 id를 get으로 요청하면 정상적으로 해당 유저의 정보가 출력됨.


없는 id로 요청 시 NO_CONTENT로 지정해뒀으므로 아무 정보도 나타나지 않음.
리스트로 저장했기때문에 서버를 내리면 생성한 유저가 초기화되므로 테스트 시 주의.


PUT 유저정보 업데이트하기


새 클래스 생성

- UpdateUserRequest -

public class UpdateUserRequest {
	// 유저 객체에서 email을 제외한 name만 업데이트
    @Size(min = 2, message = "이름의 길이는 2자 이상")
	private String name;
    // getset 자동생성
}

- UserController -

// 업데이트 시 id를 입력 후 body에 업데이트 할 이름을 json으로 입력함
@PutMapping("/{userId}")
public UserRest getUpdateUser(@PathVariable("userId") String id,
							@Valid @RequestBody UpdateUserRequest user) {
	UserRest savedUser = users.get(id);
	savedUser.setName(user.getName());		// 이름 수정됨
	
	return savedUser;
}

입력한 userId로 유저를 찾은 후
@Valid로 유효성을 검증,
검증을 마친 name을 @RequestBody로 내용을 넣어 업데이트한다.


DELETE 유저 삭제하기

- UserController -

@DeleteMapping("/{userId}")
public ResponseEntity<Void> geDeletetUser(@PathVariable("userId") String id) {
	users.remove(id);
	return new ResponseEntity<Void>(HttpStatus.NO_CONTENT);
}


새 유저 생성 후 생성된 id로 delete요청 > 삭제 후 GET으로 id를 검색해보면 no content로 뜨는것을 확인할 수 있음.


pma 프로젝트에 rest api적용하기 -1-

GET으로 직원 검색하기


새 클래스, 패키지 생성

- EmployeeApiController -

@RestController
@RequestMapping("/app-api/employees")
public class EmployeeApiController {
	
	@Autowired
	private EmployeeRepository empRepo;
	
	@GetMapping
	public Iterable<Employee> getEmployees(){
		return empRepo.findAll();
	}
}

- Employee -
무한반복 방지를 위해 @JsonIgnore추가

// N:N 관계에서는 테이블을 만들어 만든 테이블에 id를 넣고 다른 테이블의 id도 입력한다.
// CascadeType.PERSIST, CascadeType.REMOVE 제거
@ManyToMany(cascade = {CascadeType.MERGE, CascadeType.REFRESH, CascadeType.DETACH}, fetch = FetchType.LAZY)  
@JoinTable(name = "project_employee", joinColumns = @JoinColumn(name="employee_id"),
				inverseJoinColumns = @JoinColumn(name="project_id"))
@JsonIgnore		// 이게 없으면 무한으로 서로 검색해서 호출함
private List<Project> projects;


http://localhost:8080/app-api/employees 로 실행시 모든 직원들의 명단이 json으로 출력됨.

- EmployeeApiController -
id로 직원을 찾는 메서드 추가

@GetMapping("/{id}")
public Employee getEmployeeById(@PathVariable("id") Long id){
	return empRepo.findByEmployeeId(id);
}


http://localhost:8080/app-api/employees/1 검색 시 해당 id의 직원정보가 json으로 출력됨.


POST로 새 직원 입력하기

- EmployeeApiController -

// 요청하는 body에 json타입의 새 직원 데이터를 입력 시 새 직원 생성 후 그 직원을 리턴
@PostMapping(consumes = "application/json")
@ResponseStatus(HttpStatus.CREATED)		// 상태 201 생성
public Employee create(@RequestBody Employee employee){
	return empRepo.save(employee);
}

postman으로 입력 테스트 하기전, csrf설정을 끔
- SecurityConfiguration -

@Override
protected void configure(HttpSecurity http) throws Exception {	
	...
    http.csrf().disable();	// REST API에서는 csrf설정을 끔
}


테스트 시 새 직원을 생성 후 그 직원의 데이터를 리턴함.
생성된 employeeId로 검색해보면 같은 결과가 나옴.
여기서는 없는 id로 저장을 요청했기 때문에 새 직원이 저장된 것.
(이전 수업에서 empRepo.save(employee)시 id를 검색해 있으면 update작업을, 없으면 save로 새 직원을 만드는 작업을 하도록 작성하였음.)

좋은 웹페이지 즐겨찾기