pom.xml
@@ -521,6 +521,17 @@ <version>0.9.1</version> </dependency> <!-- Swagger(api 문서화) --> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>2.9.2</version> </dependency> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger-ui</artifactId> <version>2.9.2</version> </dependency> </dependencies> <repositories> src/main/java/kr/wisestone/owl/config/SecurityConfiguration.java
@@ -145,7 +145,9 @@ .antMatchers("/language/change").permitAll() .antMatchers("/security/*").permitAll() .antMatchers("/api/issue").permitAll() .antMatchers("/api/issue/*").permitAll() .antMatchers("/**/*").authenticated(); // http.addFilter(new CustomAuthenticationFilter()); // http.addFilterBefore(new CustomAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class); src/main/java/kr/wisestone/owl/config/SwaggerConfig.java
New file @@ -0,0 +1,94 @@ package kr.wisestone.owl.config; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import springfox.documentation.builders.ApiInfoBuilder; import springfox.documentation.builders.PathSelectors; import springfox.documentation.builders.RequestHandlerSelectors; import springfox.documentation.service.ApiInfo; import springfox.documentation.service.Parameter; import springfox.documentation.spi.DocumentationType; import springfox.documentation.spring.web.plugins.Docket; import springfox.documentation.swagger2.annotations.EnableSwagger2; /** * API 문서 제작 패키지 Swagger 설정 클래스 */ @Configuration @EnableSwagger2 public class SwaggerConfig { private static final String API_NAME = "OWL API"; private static final String API_VERSION = "1.0.0"; private static final String API_DESCRIPTION = "OWL API 명세서"; /** * API 설정 * @return docket class */ @Bean public Docket api() { // Parameter parameterBuilder = new ParameterBuilder() // .name(HttpHeaders.AUTHORIZATION) // .description("Access Tocken") // .modelRef(new ModelRef("string")) // .parameterType("header") // .required(false) // .build(); List<Parameter> globalParameters = new ArrayList<>(); // globalParameters.add(parameterBuilder); return new Docket(DocumentationType.SWAGGER_2) .globalOperationParameters(globalParameters) .consumes(getConsumeContentTypes()) .produces(getProduceContentTypes()) .apiInfo(apiInfo()) .select() .apis(RequestHandlerSelectors.basePackage("kr.wisestone.owl.web.controller.Api")) .paths(PathSelectors.any()) .build(); } /** * API 문서 타이틀/버전/설명 설정 * @return ApiInfo 클래스 */ public ApiInfo apiInfo() { return new ApiInfoBuilder() .title(API_NAME) .version(API_VERSION) .description(API_DESCRIPTION) .build(); } /** * API 문서 테스트 Request Content-Type 설정 추가 * @return consumes content-type 목록 */ private Set<String> getConsumeContentTypes() { Set<String> consumes = new HashSet<>(); consumes.add("application/json;charset=UTF-8"); consumes.add("application/x-www-form-urlencoded"); return consumes; } /** * API 문서 테스트 Response content-type 설정 추가 * @return produce content-type 목록 */ private Set<String> getProduceContentTypes() { Set<String> produces = new HashSet<>(); produces.add("application/json;charset=UTF-8"); return produces; } } src/main/java/kr/wisestone/owl/service/impl/IssueServiceImpl.java
@@ -283,7 +283,7 @@ issueApiForm.addUseIssueCustomFieldId(customFieldApiOverlap.getCustomField().getId()); } // 중복된 이슈검색 // 종료상태가 아닌 중복된 상위 이슈검색 List<Issue> issues = this.findIssue(issueApiForm, customFieldApiOverlaps, user.getId()); int size = issues.size(); if (size > 0) { @@ -440,6 +440,7 @@ issueCustomFieldValueCondition.setUseValue(concatUseValue); issueCustomFieldValueCondition.setUseValues(userValues); issueCustomFieldValueCondition.setIssueTypeId(issueApiform.getIssueTypeId()); issueCustomFieldValueCondition.setIssueStatusType("CLOSE"); List<Map<String, Object>> results = this.issueMapper.findByCustomFieldValue(issueCustomFieldValueCondition); if (results != null && results.size() > 0) { for (Map<String, Object> result : results) { @@ -938,7 +939,7 @@ // if (!this.userWorkspaceService.checkWorkspaceManager(user) // && !MngPermission.checkMngPermission(userLevel.getPermission(), MngPermission.USER_PERMISSION_MNG_ISSUE)) { //최고관리자 & 프로젝트,이슈 관리자 일 경우 모든 이슈 보기 // this.SetMyDepartmentId(issueCondition); //this.SetAllDepartmentId(issueCondition); //this.SetAllDepartmentId(issueCondition); // } /*else{ // results = this.issueMapper.findByDepartment(issueCondition); // totalCount = this.issueMapper.countByDepartment(issueCondition); src/main/java/kr/wisestone/owl/web/condition/IssueCustomFieldValueCondition.java
@@ -10,6 +10,7 @@ import java.util.Map; /** * 이슈 사용자 정의 필드 값 검색 조건 클래스 * Created by wisestone on 2018-06-07. */ public class IssueCustomFieldValueCondition { @@ -17,9 +18,19 @@ private Long workspaceId; private Long customFieldId; private String customFieldType; private List<String> useValues = Lists.newArrayList(); // 단일, 다중 일때 검색 값 private String useValue; // 텍스트 필드일 때 검색 값 /** * 사용자 정의 필드 사용 값 */ private List<String> useValues = Lists.newArrayList(); /** * 텍스트 필드일 때 검색 값 */ private String useValue; private boolean useParentIssueId = true; /** * 이슈 상태 유형(READY / OPEN / CLOSE) */ private String issueStatusType; public IssueCustomFieldValueCondition(){} @@ -62,6 +73,14 @@ return condition; } public String getIssueStatusType() { return issueStatusType; } public void setIssueStatusType(String issueStatusType) { this.issueStatusType = issueStatusType; } public Long getIssueTypeId() { return issueTypeId; } src/main/java/kr/wisestone/owl/web/controller/Api/ApiController.java
New file @@ -0,0 +1,98 @@ package kr.wisestone.owl.web.controller.Api; import io.swagger.annotations.ApiImplicitParam; import io.swagger.annotations.ApiOperation; import kr.wisestone.owl.constant.MsgConstants; import kr.wisestone.owl.domain.Issue; import kr.wisestone.owl.exception.OwlRuntimeException; import kr.wisestone.owl.service.IssueService; import kr.wisestone.owl.util.ConvertUtil; import kr.wisestone.owl.web.controller.BaseController; import kr.wisestone.owl.web.form.ApiIssueAddForm; import kr.wisestone.owl.web.form.ApiIssueModifyForm; import kr.wisestone.owl.web.form.IssueApiForm; import org.json.simple.parser.ParseException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * OWL-API 컨트롤러 */ @Controller @RequestMapping("/api") public class ApiController extends BaseController { @Autowired private IssueService issueService; /** * 이슈 추가 * @param apiIssueAddForm 입력 폼 데이터 * @param files 파일 * @return JSON * @throws OwlRuntimeException 파라미터 오류시 발생 * @throws CloneNotSupportedException 이슈 복사 시에 발생 */ @PostMapping(value = "/issue") @ApiOperation(value = "이슈 추가", notes = "새로운 이슈를 추가한다.") @ApiImplicitParam(name = "files", required = false, dataType = "file") public @ResponseBody Map<String, Object> addIssue(ApiIssueAddForm apiIssueAddForm, @RequestParam("files") List<MultipartFile> files) throws OwlRuntimeException, CloneNotSupportedException, ParseException { Map<String, Object> resJsonData = new HashMap<>(); IssueApiForm issueApiForm = ConvertUtil.copyProperties(apiIssueAddForm, IssueApiForm.class); // String str = request.getParameter(Constants.REQ_KEY_CONTENT); issueApiForm.setMultipartFiles(files); issueApiForm.parseCustomFields(apiIssueAddForm.getCustomFields()); issueApiForm.setApiType(IssueApiForm.ApiType.add); // 사용자 정의 필드가 없을 경우 검색을 할 수 없기 때문에 예외처리 if (issueApiForm.getCustomFieldValues() == null || issueApiForm.getCustomFieldValues().size() == 0) { throw new OwlRuntimeException(this.messageAccessor.getMessage(MsgConstants.API_CUSTOM_FIELD_NOT_EXIST)); } List<Issue> issues = this.issueService.addApiIssue(issueApiForm); // 버전 생성 for (Issue issue : issues) { this.issueService.addIssueVersion(issue.getId(), issue.getRegisterId()); } return this.setSuccessMessage(resJsonData); } /** * 이슈 상태 수정 * @param apiIssueModifyForm 수정 폼 데이터 * @return JSON * @throws OwlRuntimeException 파라미터 오류시 발생 * @throws CloneNotSupportedException 이슈 복사 시에 발생 */ @PostMapping(value = "/issue/1") @ApiOperation(value = "이슈 상태 수정", notes = "사용자 정의 필드가 동일한 기존 이슈를 변경한다.") public @ResponseBody Map<String, Object> modifyIssue(ApiIssueModifyForm apiIssueModifyForm) throws OwlRuntimeException, CloneNotSupportedException, ParseException { Map<String, Object> resJsonData = new HashMap<>(); IssueApiForm issueApiForm = ConvertUtil.copyProperties(apiIssueModifyForm, IssueApiForm.class); issueApiForm.parseCustomFields(apiIssueModifyForm.getCustomFields()); issueApiForm.setApiType(IssueApiForm.ApiType.add); // 사용자 정의 필드가 없을 경우 검색을 할 수 없기 때문에 예외처리 if (issueApiForm.getCustomFieldValues() == null || issueApiForm.getCustomFieldValues().size() == 0) { throw new OwlRuntimeException(this.messageAccessor.getMessage(MsgConstants.API_CUSTOM_FIELD_NOT_EXIST)); } this.issueService.modifyIssue(issueApiForm, new ArrayList<>()); return this.setSuccessMessage(resJsonData); } } src/main/java/kr/wisestone/owl/web/controller/ApiController.java
File was deleted src/main/java/kr/wisestone/owl/web/controller/ApiTokenController.java
@@ -6,6 +6,7 @@ import kr.wisestone.owl.util.ConvertUtil; import kr.wisestone.owl.vo.ApiTokenVo; import kr.wisestone.owl.web.condition.ApiTokenCondition; import kr.wisestone.owl.web.controller.BaseController; import kr.wisestone.owl.web.form.ApiTokenForm; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.domain.Pageable; @@ -20,13 +21,20 @@ import java.util.List; import java.util.Map; /** * API 토큰 컨트롤러 클래스 */ @Controller public class ApiTokenController extends BaseController { @Autowired private ApiTokenService apiTokenService; // 토큰 생성 /** * 토큰 생성 * @param params 토큰 생성에 필요한 파라미터 * @return 생성 결과 Map<String, Object> */ @RequestMapping(value = "/apiToken/add", produces = MediaType.APPLICATION_JSON_VALUE) public @ResponseBody @@ -41,6 +49,12 @@ return this.setSuccessMessage(resJsonData); } /** * 토큰 조회 * @param params 토큰 조회에 필요한 파라미터 * @return 조회 결과, Map<String, ApiTokenVo> */ // 토큰 조회 @RequestMapping(value = "/apiToken/find", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE) public @@ -55,6 +69,11 @@ return this.setSuccessMessage(resJsonData); } /** * 토큰 삭제 * @param params 토큰 삭제에 필요한 파라미터 * @return 삭제 결과, Map<String, Object> */ // 토큰 삭제 @RequestMapping(value = "/apiToken/remove", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE) public src/main/java/kr/wisestone/owl/web/form/ApiIssueAddForm.java
New file @@ -0,0 +1,53 @@ package kr.wisestone.owl.web.form; import io.swagger.annotations.ApiParam; /** * API 이슈 추가용 Form class */ public class ApiIssueAddForm { @ApiParam(value = "사용자 토큰", required = true) private String token; @ApiParam(value = "이슈 제목") private String title; @ApiParam(value = "이슈 타입 ID", required = true) private Long issueTypeId; @ApiParam(value = "사용자 정의 필드", required = true) private String customFields; public ApiIssueAddForm() { } public String getCustomFields() { return customFields; } public void setCustomFields(String customFields) { this.customFields = customFields; } public String getToken() { return token; } public void setToken(String token) { this.token = token; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public Long getIssueTypeId() { return issueTypeId; } public void setIssueTypeId(Long issueTypeId) { this.issueTypeId = issueTypeId; } } src/main/java/kr/wisestone/owl/web/form/ApiIssueModifyForm.java
New file @@ -0,0 +1,63 @@ package kr.wisestone.owl.web.form; import io.swagger.annotations.ApiParam; /** * API 이슈 상태 수정용 Form class */ public class ApiIssueModifyForm { @ApiParam(value = "사용자 토큰", required = true) private String token; @ApiParam(value = "이슈 타입 ID", required = true) private Long issueTypeId; @ApiParam(value = "이슈 상태 ID", required = true) private Long issueStatusId; @ApiParam(value = "댓글", required = true) private String comment; @ApiParam(value = "사용자 정의 필드", required = true) private String customFields; public ApiIssueModifyForm() { } public Long getIssueTypeId() { return issueTypeId; } public void setIssueTypeId(Long issueTypeId) { this.issueTypeId = issueTypeId; } public Long getIssueStatusId() { return issueStatusId; } public void setIssueStatusId(Long issueStatusId) { this.issueStatusId = issueStatusId; } public String getToken() { return token; } public void setToken(String token) { this.token = token; } public String getComment() { return comment; } public void setComment(String comment) { this.comment = comment; } public String getCustomFields() { return customFields; } public void setCustomFields(String customFields) { this.customFields = customFields; } } src/main/java/kr/wisestone/owl/web/form/ApiTokenForm.java
@@ -1,13 +1,11 @@ package kr.wisestone.owl.web.form; import com.google.common.collect.Lists; import kr.wisestone.owl.domain.User; import kr.wisestone.owl.util.ConvertUtil; import kr.wisestone.owl.util.MapUtil; import java.util.List; import java.util.Map; /** * API 토큰 Form class */ public class ApiTokenForm { private Long id; private User user; src/main/java/kr/wisestone/owl/web/form/IssueApiForm.java
@@ -4,10 +4,13 @@ import kr.wisestone.owl.util.ConvertUtil; import kr.wisestone.owl.util.MapUtil; import org.springframework.web.multipart.MultipartFile; import java.io.Serializable; import java.util.*; public class IssueApiForm { /** * API 이슈 추가 / 수정용 form class */ public class IssueApiForm implements Serializable { public enum ApiType { add, @@ -37,44 +40,30 @@ public IssueApiForm() { } public static IssueApiForm make(Map<String, Object> content, List<MultipartFile> files) { IssueApiForm form = ConvertUtil.convertMapToClass(content, IssueApiForm.class); form.setMultipartFiles(files); // api 타입 if (MapUtil.getString(content, "apiType") != null) { try { form.setApiType(ApiType.valueOf(MapUtil.getString(content, "apiType"))); } catch (Exception ex) { return null; } /** * 사용자 정의 필드 변환 * @param customFieldJson 사용자 정의 필드 json */ public void parseCustomFields(String customFieldJson) { Map<String, Object> json = ConvertUtil.convertJsonToMap(customFieldJson); List<Map<String, Object>> customFields = (List) MapUtil.getObject(json, "customFields"); for (Map<String, Object> customField : customFields) { IssueCustomFieldValueForm issueCustomFieldValueForm = ConvertUtil.convertMapToClass(customField, IssueCustomFieldValueForm.class); this.addIssueCustomFieldValue(issueCustomFieldValueForm); Map<String, Object> customFieldVo = new HashMap<>(); customFieldVo.put("id", issueCustomFieldValueForm.getCustomFieldId()); customField.put("customFieldVo", customFieldVo); List<String> useValues = Lists.newArrayList(); useValues.add(issueCustomFieldValueForm.getUseValue()); customField.put("useValues", useValues); this.addCustomFieldValue(customField); } // 사용자 필드 정보 if (MapUtil.getObject(content, "customFields") != null){ List<Map<String, Object>> customFields = (List)MapUtil.getObject(content, "customFields"); for (Map<String, Object> customField : customFields) { IssueCustomFieldValueForm issueCustomFieldValueForm = ConvertUtil.convertMapToClass(customField, IssueCustomFieldValueForm.class); form.addIssueCustomFieldValue(issueCustomFieldValueForm); Map<String, Object> customFieldVo = new HashMap<>(); customFieldVo.put("id", issueCustomFieldValueForm.getCustomFieldId()); customField.put("customFieldVo", customFieldVo); List<String> useValues = Lists.newArrayList(); useValues.add(issueCustomFieldValueForm.getUseValue()); customField.put("useValues", useValues); form.addCustomFieldValue(customField); } } // 첨부 파일 // if (MapUtil.getObject(content, "files") != null){ // form.setFiles((List)MapUtil.getObject(content, "files")); // } return form; } public String getToken() { src/main/resources/log4j2.xml
@@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8"?> <Configuration status="warn" name="owl-its" monitorInterval="600"> <Configuration status="ERROR" name="owl-its" monitorInterval="600"> <Properties> <Property name="LOG_FORMAT">%d{yyyy-MM-dd HH:mm:ss} [%level] - %msg%n</Property> <Property name="BASE_DIR">/owl-enterprise-logs</Property> @@ -50,6 +50,12 @@ <AppenderRef ref="File"/> </Logger> <!-- Crawling Logger --> <Logger name="kr.wisestone.owl.crawling" level="debug" additivity="false"> <AppenderRef ref="Console"/> <AppenderRef ref="File"/> </Logger> <!-- Root Loggers --> <Root level="warn"> <AppenderRef ref="Console"/> src/main/resources/mybatis/query-template/issue-template.xml
@@ -1115,8 +1115,12 @@ </when> </choose> ) customFieldValue ON customFieldValue.issueId = issue.id WHERE issStatus.issue_status_type != 'CLOSE' AND issue.issue_type_id = #{issueTypeId} WHERE issue.issue_type_id = #{issueTypeId} <choose> <when test="issueStatusType != null"> AND issStatus.issue_status_type != #{issueStatusType} </when> </choose> GROUP BY issue.id HAVING concatUseValue LIKE CONCAT('%', #{useValue}, '%') </select>