프로비저닝

개요
시작하며 
 
 프로비저닝은 IT 인프라를 생성하고 설정하는 프로세스 입니다. 이 예제에서는 회사의 조직도와 Swit의 조직도를 연동하는 과정을 설명합니다. 
 가이드에 앞서 시작 및 준비 를 먼저 해주시길 바랍니다. 
 API호출시 사용되는 get 및 post 는 RestfulAPI 를 참조해주세요. 
 
 
 프로비저닝 과정 
 조직도 생성 
 
 조직원 구성 
 
 조직 부서 제외

팀 생성
Swit Team 정보 생성 
 
 
 Swit 의 Team API를 이용하여 팀을 생성 합니다. 
 상위조직의 아이디는 필수값이므로 상위조직부터 생성하시길 바랍니다. 
 최상위 조직을 등록하실땐 parent_id를 0으로 주시면 됩니다. 
 
 
 package io.swit.api.service.eai;

@Service
@Slf4j
@AllArgsConstructor
public class TeamService {
 public String createSwitTeam(SwitDeptDto team) throws Exception{
 String teamId = "";
 JSONObject params = new JSONObject();
 try {
 params.put("name", team.getTeamName());
 params.put("parent_id", team.getParentId());
 params.put("reference", team.getReference());

 SwitTokenDto tokenDto = authService.getSwitTokenByDb("cts-api");
 JsonObject result = httpUtils.post("team.create", params, tokenDto);
 JsonElement data = result.getAsJsonObject().get("data");
 SwitDeptDto switDept = new SwitDeptDto();
 switDept = this.parsingTeamResult(data);
 teamId = this.saveSwitDeptBySync(switDept);
 } catch (Exception e) {
 log.error(e.getMessage());
 }

 return teamId;
 }
}

팀 리스트 불러오기
Swit Team 리스트 
 
 
 Swit 의 Team List API를 이용하여 팀 목록을 불러옵니다. 
 팀 데이터 안에 소속된 유저의 아이디 배열이 포함되어 있습니다. 
 
 
 public List<SwitDeptDto> getSwitTDeptByAPI() throws Exception {
 List<SwitDeptDto> list = new ArrayList<>();
 try {

 SwitTokenDto tokenDto = authService.getSwitTokenByDb("cts-api");
 JsonObject jsonObject = httpUtils.get("user.team.list", tokenDto) ;
 JsonElement data = jsonObject.get("data");

 // 유저목록 가져오기
 JsonArray teams = data.getAsJsonObject().get("team").getAsJsonArray();
 for (JsonElement team: teams) {
 SwitDeptDto teamDto = new SwitDeptDto();
 teamDto.setTeamId(team.getAsJsonObject().get("team_id").toString().trim().replaceAll("\"", ""));
 teamDto.setTeamName(team.getAsJsonObject().get("team_name").toString().trim().replaceAll("\"", ""));
 teamDto.setParentId(team.getAsJsonObject().get("parent_id").toString().trim().replaceAll("\"", ""));
 teamDto.setDepth(Integer.parseInt(team.getAsJsonObject().get("depth").toString().trim()));
 teamDto.setMemberCnt(Integer.parseInt(team.getAsJsonObject().get("member_cnt").toString().trim()));
 teamDto.setReference(team.getAsJsonObject().get("reference").toString().trim().replaceAll("\"",""));
 //팀 사용자 정보
 JsonArray users = team.getAsJsonObject().get("users").getAsJsonArray();
 List<String> userList = new ArrayList<>();
 for (int i = 0; i < users.size(); i++) {
 userList.add(users.get(i).toString().trim());
 }
 teamDto.setUsers(userList);
 list.add(teamDto);
 }
 } catch (Exception e) {
 log.error(e.getMessage());
 }
 return list;
 }

사용자 등록
Swit User 생성 
 
 
 Swit 의 User API를 이용하여 사용자를 등록 합니다. 
 소속팀 정보는 유저를 생성후 유저아이디를 가지고 생성되어 있는 팀에 추가 시켜줘야 합니다. 
 
 
 public HrUserDto createSwitUser(SwitUserDto user) throws Exception {
 HrUserDto hrUserDto = new HrUserDto();
 try {
 // 유저생성 파라미터를 설정한다.
 JSONObject params = new JSONObject();
 params.put("language", user.getLanguage());
 params.put("timezone", user.getTimezone());
 params.put("user_name", user.getUserName());
 params.put("user_email", user.getEmail());
 params.put("tel", user.getTel());
 params.put("msg", user.getMsg());

 SwitTokenDto tokenDto = authService.getSwitTokenByDb("cts-api");
 JsonObject result = httpUtils.post("organization.user.create", params, tokenDto);

 // 팀에 유저 추가 및 메인팀 설정 (Team에 유저 등록하면 main_dept_yn 자동 Y)
 List<String> userIds = new ArrayList<String>();
 userIds.add(result.get("data").getAsJsonObject().get("user").getAsJsonObject().get("user_id").getAsString());
 teamService.addUserToSwitTeam(user.getTeamId(), userIds); // return값 없음
 } catch (Exception e) {
 log.error(e.getMessage());
 throw new Exception(e);
 }
 return hrUserDto;
}
 
 
 팀에 유저추가 및 메인팀 설정은 사용자 팀 설정 을 참고 해 주세요.

사용자 팀 설정
Swit User 팀 등록 
 
 
 Swit 의 Team API를 이용하여 등록한 유저들을 팀에 추가 합니다. 
 소속된 팀이 없는 유저를 처음 추가하면 Main 부서로 등록되게 됩니다. 
 
 
 public SwitDeptDto addUserToSwitTeam(String teamId, List<String> userIds) throws Exception{
 SwitDeptDto retVal = new SwitDeptDto();
 JSONObject params = new JSONObject();
 try {
 JSONArray userList = new JSONArray();
 for(String id : userIds)
 userList.add(id);
 params.put("user_ids", userList);
 params.put("id", teamId);
 SwitTokenDto tokenDto = authService.getSwitTokenByDb("cts-api");

 JsonObject result = httpUtils.post("team.user.add", params, tokenDto);
 JsonElement data = result.getAsJsonObject().get("data").getAsJsonObject().get("data");
 retVal = this.parsingTeamResult(data);
 } catch (Exception e) {
 log.error(e.getMessage());
 throw new Exception(e);
 }
 return retVal;
}

사용자 리스트 불러오기
Swit User 리스트 
 
 
 
 Swit 의 User API를 이용하여 등록한 유저들의 리스트를 불러옵니다. 
 
 
 cnt(한페이지에 불러올 데이터의 갯수) 는 필수값입니다. 
 
 
 
 public List<SwitUserDto> getSwitUsersByAPI() throws Exception {
 List<SwitUserDto> list = new ArrayList<>();
 try {
 //유저 정보를 가져온다.
 SwitTokenDto tokenDto = authService.getSwitTokenByDb("cts-api");
 int page = 1;

 boolean isFinsished = true;

 while (isFinsished) {
 //100개씩 묶어서 처리한다.
 JsonObject jsonObject = httpUtils.get("organization.user.list?cnt=100&page=" + page, tokenDto) ;
 JsonElement data = jsonObject.get("data");
 JsonArray users = data.getAsJsonObject().get("users").getAsJsonArray();

 int totalRows = 0;
 totalRows = data.getAsJsonObject().get("total_rows").getAsInt();

 if (users.isEmpty() || list.size() >= totalRows) {
 isFinsished = false;
 } else {
 // 유저목록 가져오기
 for (JsonElement user : users) {
 list.add(this.switUserMappingByJson(user));
 }
 page += 1;

 }

 }
 } catch (Exception e) {
 log.error(e.getMessage());
 }
 return list;
}
 
 
 유저목록을 가져올때 Json 에서 객체로 매핑하는 함수는 여기 를 참고해 주세요

스케줄러 를 이용한 배치
기본 개념 
 1. 스케줄러 : 일정한 시간 또는 시각에 특정 로직을 실행 
 2. 배치 : 실시간이 아닌 데이터의 일괄처리 
 
 SpringBoot에서 Quartz를 이용 
 1. dependencies 에 Quartz 추가 
 implementation 'org.springframework.boot:spring-boot-starter-quartz'
 
 2. Application Class에 스케줄링 
 @SpringBootApplication
@EnableScheduling // <------ 추가
public class CtsApiJavaApplication {
	public static final String APPLICATION_LOCATIONS = "spring.config.location="
		+ "classpath:environment.yml,"
		+ "classpath:application.yml";

	public static void main(String[] args) {
		new SpringApplicationBuilder(CtsApiJavaApplication.class)
			.properties(APPLICATION_LOCATIONS)
			.run(args);
	}

}
 
 3. Job 작성 
 package io.swit.api.schedule.job;

import io.swit.api.service.com.LogService;
import io.swit.api.service.eai.SyncService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.quartz.Job;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import java.util.Map;

@Slf4j
@AllArgsConstructor
public class SyncScheduleJob implements Job { // <------ Job implements
 private SyncService syncService;
 private LogService logService;

 @Override
 public void execute(JobExecutionContext context) throws JobExecutionException { // <------ execute 메서드에 수행업무 작성
 //조직 및 구성원 동기화
 try {
 log.info("조직 및 구성원 동기화 시작");
 Map<String,Integer> result = syncService.syncSwitTeams();
 log.info(String.format("%d조직 및 %d구성원 동기화 성공",result.get("team"),result.get("teamUser")));
 } catch (Exception e) {
 log.error("조직 및 구성원 동기화 실패 : " + e.getMessage());
 try {
 logService.saveErrorLog(e, "TeamBatch");
 } catch (Exception ex) {
 throw new RuntimeException(ex);
 }
 } finally {
 log.info("조직 및 구성원 동기화 종료");
 }

 //유저정보 동기화
 try{
 log.info("유저 및 팀 유저 동기화 시작");
 Map<String,Integer> result = syncService.syncSwitUsers();
 log.info(String.format("%d명 유저 및 %d명 팀 유저 동기화 성공",result.get("user"),result.get("teamUser")));
 }catch(Exception e){
 log.error("유저 및 팀 유저 동기화 실패 : " + e.getMessage());
 try {
 logService.saveErrorLog(e, "UserBatch");
 } catch (Exception ex) {
 throw new RuntimeException(ex);
 }
 }finally {
 log.info("유저 및 팀 유저 동기화 종료");
 }
 }
}

 
 4. Schedule 작성 
 package io.swit.api.schedule.config;

import io.swit.api.schedule.job.SyncScheduleJob;
import lombok.RequiredArgsConstructor;
import org.quartz.*;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.quartz.SchedulerFactoryBean;
import javax.annotation.PostConstruct;
import java.util.TimeZone;

@Configuration
@RequiredArgsConstructor
public class SyncSchedule {
 private final SchedulerFactoryBean schedulerFactoryBean; // <------ 스케줄러빈 사용

 @PostConstruct
 public void scheduled() throws SchedulerException {
 JobDetail syncProvosioningJob = jobDetail("syncTeamUser", "Provisioning");
 CronTrigger syncProvisioningTrigger = trigger("scheduleTrigger", "trigger-group", "0 0 0/1 1/1 * ? *");
 this.schedulerFactoryBean.getScheduler().scheduleJob(syncProvosioningJob, syncProvisioningTrigger);
 }
 private JobDetail jobDetail(String name, String group){ // <------ 작성해놓은 Job class 로 JobDeail 생성
 JobDetail job = JobBuilder.newJob(SyncScheduleJob.class)
 .build();
 return job;
 }

 private CronTrigger trigger(String name, String group, String cronExpression) { // <------ 트리거 생성 ( 작성자는 크론표현식을 사용하여 크론 트리거 생성 )

 CronTrigger trigger = TriggerBuilder.newTrigger()
 .startNow()
 .withSchedule(CronScheduleBuilder.cronSchedule(cronExpression).inTimeZone(TimeZone.getTimeZone("Asia/Seoul")))
 .build();
 return trigger;
 }
}

유저 정보 매핑 ( by Json )
Json타입의 유저정보 객체로 매핑 
 
 
 Json타입으로 받은 객체정보를 Java Dto 로 매핑 
 
 
 
 private SwitUserDto switUserMappingByJson(JsonElement user) throws Exception{
 SwitUserDto retVal = new SwitUserDto();//사용자 정보
 List<SwitDeptDto> teams = new ArrayList<>(); //사용자 조직 정보

 // 사용자 정보를 가져 온다.
 retVal.setUserId(user.getAsJsonObject().get("user_id").getAsString()); //사용자 아이디
 retVal.setUserName(user.getAsJsonObject().get("user_name").getAsString()); //사용자 이름
 retVal.setEmail(user.getAsJsonObject().get("email").getAsString()); //이메일
 retVal.setRole(user.getAsJsonObject().get("role").getAsInt()); //역할코드
 retVal.setStatus(user.getAsJsonObject().get("status").getAsString()); //상태
 retVal.setMode(user.getAsJsonObject().get("mode").getAsString()); //모드?
 retVal.setTel(user.getAsJsonObject().get("tel").getAsString()); //전화번호
 retVal.setTimezone(user.getAsJsonObject().get("timezone").getAsString()); //타입존
 retVal.setTimezoneAutoFlag(user.getAsJsonObject().get("timezone_auto_flag").getAsInt()); //타임존 자동 여부
 retVal.setMsg(user.getAsJsonObject().get("msg").getAsString());
 retVal.setBgColor(user.getAsJsonObject().get("bg_color").getAsString()); //배경색
 retVal.setPhoto(user.getAsJsonObject().get("photo").getAsString()); //프로필 이미지
 retVal.setActive(user.getAsJsonObject().get("is_active").getAsBoolean()); //활성화 여부
 retVal.setLanguage(user.getAsJsonObject().get("language").getAsString().trim()); //사용언언
 // 날짜 포맷을 맞춰 준다.
 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
 if (StringUtils.hasText(user.getAsJsonObject().get("created").getAsString())) {
 Date createdDate = sdf.parse(user.getAsJsonObject().get("created").getAsString().trim().replace("T", " ").replace("Z", ""));
 LocalDateTime created = LocalDateTime.ofInstant(createdDate.toInstant(), ZoneId.of("Asia/Seoul"));
 retVal.setCreated(created);
 }
 if (StringUtils.hasText(user.getAsJsonObject().get("last_activity").getAsString())) {
 Date lastActivityDate = sdf.parse(user.getAsJsonObject().get("last_activity").getAsString().trim().replace("T", " ").replace("Z", ""));
 LocalDateTime lastActivity = LocalDateTime.ofInstant(lastActivityDate.toInstant(), ZoneId.of("Asia/Seoul"));
 retVal.setLastActivity(lastActivity);
 }

 // 팀 정보
 if (user.getAsJsonObject().get("team") != null && !user.getAsJsonObject().get("team").toString().equals("null")) {
 JsonArray userTeams = user.getAsJsonObject().get("team").getAsJsonArray();
 for (JsonElement team : userTeams) {
 SwitDeptDto teamDto = new SwitDeptDto();
 teamDto.setTeamId(team.getAsJsonObject().get("team_id").getAsString());
 teamDto.setTeamName(team.getAsJsonObject().get("team_name").getAsString());
 teamDto.setMainDeptYn(team.getAsJsonObject().get("main_dept_yn").getAsString());
 teams.add(teamDto);
 //메인부서일 경우 등록해 준다.
 if (StringUtils.hasText(teamDto.getMainDeptYn())
 && "Y".equalsIgnoreCase(teamDto.getMainDeptYn())) {
 retVal.setTeamId(teamDto.getTeamId());
 retVal.setTeamName(teamDto.getTeamName());
 }
 }
 }
 retVal.setTeam(teams);
 return retVal;
}