반응형

1. 팀 등록

 

팀을 등록할 api의 명세이다.

요구사항은 간단하지만 막상 구현하려면 이렇게 간단하게만 작성할수는없다.

비즈니스적으로 예외사항에대한 처리를 해줘야하고

파라미터로 들어오는값도 검증이 필요하다면 해주어야한다.

 

팀 등록기능 

1. 팀을 등록할때에는 팀 이름을 필수로 가져야한다.

 

예외처리

1. 동일한 이름의 팀등록은 제외한다.

 

Controller

@RestController
@RequestMapping("/team")
public class TeamController {

    private final TeamService service;

    public TeamController(TeamService service) {
        this.service = service;
    }

    @PostMapping
    public void registerTeam(@RequestBody Map<String, String> requestJson){
        service.registerTeam(requestJson.get("teamName"));
    }
}

Repository

public interface TeamRepository extends JpaRepository<Team,Long> {
    Team findByTeamName(String teamName);
    
    //팀 이름을 조회하여 있으면 true 없으면 false를 리턴
    Boolean existsByTeamName(String teamName);
}

Service

@Service
public class TeamService {

    private final TeamRepository repository;

    public TeamService(TeamRepository repository) {
        this.repository = repository;
    }

    public void registerTeam(String teamName) {
    	//이미 있는 팀이름을 등록하는 경우 에러처리
   	//팀 이름을 키로 지정해도 같은 문제를 해결할수있을것같다.
        if(isExistTeam(teamName)){
            throw new IllegalArgumentException("이미 존재하는 팀 이름입니다: " + teamName);
        }
        repository.save(new Team(teamName));
    }
    
    private boolean isExistTeam(String name){
        return repository.existsByTeamName(name);
    }
}

 


 

 

디자인팀이 데이터베이스에 잘 저장되었다. 

같은 이름의 팀을 저장해보자.

 

 


 

동일한 이름의 팀을 저장하려고 시도하면 

에러가 발생한다.

 

 

 


 

이미 존재하는 팀의 이름을 저장하려고 하면 에러가 발생하는것을 볼수있다. 

api응답으로도 에러메시지를 받을수있는데 이경우에는 controller에서 ResponseEntity를 리턴해줘야하는것 같다.

간단한 저장이라서 응답없이 처리하도록 해주었기때문에

api응답은 에러의 발생원인이 서버에게있다고하는 500에러를 보내게된다. 

 

여기서 문제가 발생한다. 에러를 발생시킨부분은 서버가 맞지만 잘못된 요청으로 인해 에러가 발생한것으로 

다시 잘 요청해달라는 의미로 클라이언트 에러인 400번대 에러를 보내줘야한다. (클라이언트 너의 책임이다!)

 

여기서 스프링 Controller의 에러처리 기능인 @RestControllerAdvice를 사용해주었다. (처음 써봤다.)

 


@RestControllerAdvice , @ControllerAdvice

두 어노테이션 모두 스프링에서 Controller의 전역적인 에러처리를 위해서 사용된다. 

@ControllerAdvice

페이지가 있는 컨트롤러에서 이용되며

주로 에러페이지로 이동하는데 사용한다고 한다(아직 안써봄)

 

@RestController

에러메시지를 Json으로 내려줄수있어서 api를 개발할때 사용한다(적용).

RestControllerAdvice는 ControllerAdvice를 포함하고있다

 

@RestControllerAdvice
public class commuteServiceException {

    @ExceptionHandler(IllegalArgumentException.class)
    public ResponseEntity<String> illegalArgumentExceptionHandle(IllegalArgumentException e) {
        return ResponseEntity.badRequest().body("error : " + e.getMessage());
    }

}

 

이렇게 에러를 처리해줄 클래스를 만들고 @RestControllerAdvice어노테이션을 달아주면 

컨트롤러에서 IllegarArgumentException이 발생했을때  모두 여기서 처리해서 에러응답을 보내주게된다.

에러코드는 400으로 나온다. badRequest

 

이제 팀을 저장하는 기능이끝났다. 


2. 팀장 등록

추가적인 기능을 위해

팀 테이블에 팀장의 컬럼을 추가시켜서

이 팀의 팀장이 누구인지의 데이터를 가질수있게 처리해줬다.

팀을 저장할때는 팀의 이름만 저장하기때문에 팀장값은 null로 가지고있을것이다.  

이제 이 팀장을 지정해주는 기능을 만들어주어야한다.

 

요구사항

1. 직원의 정보를 보내서 팀장을 저장할수있게해준다.

 

예외처리. 

x.

 

따로 예외처리를 해주지는 않았지만 나중에 비즈니스 요구사항에 따라 다양한 예외처리가 추가될수있을것같다.

특정 직급이상만 팀장으로 등록이 가능하다거나.

특정 직원은 등록이 불가능하게 처리한다거나 할수있을듯하다. 

(현재는 딱히 필요없어보여서 생략)

//DTO
public class TeamSetDto {
    private String teamName;
    private Integer leaderCode; // 팀장의 이름이나 id 둘중의 하나만 가지면 될것같음
    //private String leaderName;
}

//jpa를 통해서 id 나 이름이 있다면 직원정보를 조회할수있기때문에 두개중에 하나만있다면 
//조회해서 다른정보를 불러서 사용이 가능하다.

//Controller
@PostMapping("/setLeader")
public void setTeamLeader(@RequestBody TeamSetDto request){
    service.registerTeamLeader(request);
}

//Service
@Transactional
    public void registerTeamLeader(TeamSetDto request) {
        Team team = repository.findByTeamName(request.getTeamName());
        team.setTeamLeader(request.getLeaderCode());
    }
    
//팀원의 이름이나 정보로조회해서 저장하는경우.
@Transactional
    public void registerTeamLeader(TeamSetDto request) {
        Team team = repository.findByTeamName(request.getTeamName());
        Employee employee = memberRepository.findByName(request.getName());
        team.setTeamLeader(employee.getId());
    }

 

각 계층에서 추가한부분만 옮겨봤다.

팀의 정보와 팀장으로저장할 직원의 정보를받아서 팀에 넣어주면

영속성컨텍스트에의해 조회한 team 인스턴스가 변경된걸 캐치해서

자동으로 업데이트 해주게된다. 

 

개인적인 생각

지금은 그냥 postman을 통해서 요청값을 세팅하기때문에 문자열정보인 String이 더 편하지만

추후에 개발시에 프론트를 구성한다면 직원정보를 조회하고

보이는쪽은이름 실제 보내지는 value쪽은 직원의 id값이 들어가서

api에 id로 요청하는게 더 수월해지기때문에 id가 필요한 api로 개발하는게 더 좋은것같다.

조회는 id로 해야 db의 index로 인해서 더 빠르다는 얘기도 들어본것같은...

 

 

 


3. 팀 조회기능

//DTO
@Getter
@AllArgsConstructor // Jpa매핑용 , 모든파라미터생성자
public class TeamResponse {
    private String name;
    private String manager;
    private Long count;
}

//Controller
@GetMapping
public List<TeamResponse> getTeam(){
    return service.getTeam();
}

//Service
public List<TeamResponse> getTeam(){
        return repository.getAllTeam();
    }
    
//Repository
// Jpql사용
@Query("SELECT new Company.demo.commute.dto.response.TeamResponse(a.teamName, b.name, COUNT(c.id)) " +
                  "FROM Team a " +
                  "LEFT JOIN Employee b ON a.teamLeader = b " +
                  "LEFT JOIN Employee c ON a.teamId = c.team.teamId " +
                  "GROUP BY a.teamName, b.name")
    List<TeamResponse> getAllTeam();

조회결과.

 

이번에는 Jpql로 데이터를 조회했다.

jpa로 응답객체를 내주는데에는 여러가지방법이있는데 간단한조회라면 

그냥 객체를 findby로 조회해서 서비스레이어에서 매핑해서 응답객체를 내주는것도 괜찮은 방법인것같다. 

여기서는 팀장의 이름을 알아내기위해 직원 테이블도 조인해줘야하고 팀의 총인원을 집계해줘야해서

단순조회로는 코드가 너무 길어질것같아서 쿼리로 처리해 주었다.

Jpql에서 join을 사용하려면 Entity객체에서도 관계설정이 되어있어야한다.

이로인해서 기존 Entity코드에도 변경이 생겼다.

 

Team (Entity)

@Entity
@Getter
@NoArgsConstructor
public class Team {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long teamId;
    
    private String teamName;
    
    @OneToOne
    @JoinColumn(name = "team_leader_id")
    private Employee teamLeader;
    //private Integer teamLeaderId;
    
    private Integer annualLeaveBefore;

    @OneToMany(mappedBy = "team")
    private List<Employee> employeeList;

    public Team(String positionName) {
        this.teamName = positionName;
    }

    public void setTeamLeader(Employee leader) {
        this.teamLeader = leader;
    }
    // public void setTeamLeader(Integer leaderCode){
    //  this.teamLeaderId = leaderCode;
    // }
}

Team 엔티티 객체에서 기존에 단순히 팀장코드를 가지고있던 필드에 관계설정을 해줘서 직원객체랑 매핑해주었다.

이렇게 해주어야 Jpql에서 join을 사용해서 테이블끼리 조인해주는게 가능했다. 

Jpql문법에 대해서는 따로 공부해본적은없는데 관계설정해주는것만생각하면 

기본 sql문과 크게 차이없이 사용이가능한것같다.

 

이렇게 미니프로젝트 팀관련 api는 모두 처리해주었다. 

다음은 직원에 관련된 api기능을 처리해주자.

 

반응형

+ Recent posts