1.Swagger 설치 및 게시판 API 문서화
스프링부트 버전 : 2.7.0
1) 라이브러리 등록
https://mvnrepository.com/search?q=springfox
pom.xml
<properties>
<java.version>11</java.version>
<swagger-version>2.9.2</swagger-version>
</properties>
<dependencies>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>${swagger-version}</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>${swagger-version}</version>
</dependency>
</dependencies>
2) Configuration 설정
SwaggerConfiguration
mport 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.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.ApiSelectorBuilder;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
@Configuration
@EnableSwagger2
public class SwaggerConfiguration {
@Bean
public Docket docker() {
ApiInfoBuilder apiInfo=new ApiInfoBuilder();
apiInfo.title(null);
apiInfo.description("API 서버 문서 입니다.");
Docket docket=new Docket(DocumentationType.SWAGGER_2);
docket.apiInfo(apiInfo.build());
ApiSelectorBuilder apis=docket.select().apis(RequestHandlerSelectors.basePackage("kr.so.songjava.mvc.controller"));
apis.paths(PathSelectors.ant("/**"));
return apis.build();
}
}
3) 컨트롤에서 설정
BoardController
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import kr.so.songjava.mvc.domain.dto.BoardDto;
import kr.so.songjava.mvc.domain.entity.Board;
import kr.so.songjava.mvc.service.BoardSevice;
@RestController
@RequestMapping("/board")
@Api(tags="게시판 API")
public class BoardController {
@Autowired
private BoardSevice boardSevice;
/** 게시판 목록리턴 */
@GetMapping("/")
@ApiOperation(value="목록조회", notes="게시물 번호에 해당하는 목록정보를 조회할수 있습니다.")
public List<Board> getList(){
return boardSevice.getList();
}
/** 게시판 상세보기 */
@GetMapping("/{boardSeq}")
@ApiOperation(value="상세조회", notes="게시물 번호에 해당하는 상세정보를 조회할수 있습니다.")
@ApiImplicitParams({
@ApiImplicitParam(name="boardSeq", value="게시물 번호", example = "1")
})
public Board get(@PathVariable int boardSeq) {
return boardSevice.get(boardSeq);
}
/** 게시판 등록/수정처리 */
@PutMapping("/save")
@ApiOperation(value="등록/수정처리", notes="신규 게시물 저장 및 기존 게시물 업데이트가 가능합니다.")
@ApiImplicitParams({
@ApiImplicitParam(name="boardSeq", value="게시물 번호", example = "1"),
@ApiImplicitParam(name="title", value="제목", example = "spring"),
@ApiImplicitParam(name="contents", value="내용", example="spring 강좌"),
})
public Integer save(BoardDto boardDto) {
return boardSevice.save(boardDto);
}
/** 게시판 삭제처리 */
@DeleteMapping("/{boardSeq}")
@ApiOperation(value="게시판 삭제처리", notes="게시물 번호에 해당하는 정보를 삭제합니다.")
@ApiImplicitParams({
@ApiImplicitParam(name="boardSeq", value="게시물 번호", example = "1")
})
public int delete(@PathVariable int boardSeq) {
return boardSevice.delete(boardSeq);
}
}
application.properties 에 추가
spring.mvc.pathmatch.matching-strategy= ant-path-matcher
4) /swagger-ui.html 실행
http://localhost:8080/swagger-ui.html

소스
https://github.com/stylehosting/example-spring
2.API 공통 Response class, enum 사용하기
BaseResponseCode
public enum BaseResponseCode {
SUCCESS(200), // 성공
ERROR(500), // 실패
;
private int status;
BaseResponseCode(int status) {
this.status = status;
}
public int status() {
return status;
}
}
BaseResponse
import lombok.Data;
@Data
public class BaseResponse<T> {
private BaseResponseCode code;
private String message;
private T data;
public BaseResponse(T data) {
this.code=BaseResponseCode.SUCCESS;
this.data=data;
}
public BaseResponse(String status, T data) {
if(status.equals("bad"))this.code=BaseResponseCode.ERROR;
else this.code=BaseResponseCode.SUCCESS;
this.data=data;
}
}
BoardController
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import kr.so.songjava.configuration.http.BaseResponse;
import kr.so.songjava.mvc.domain.dto.BoardDto;
import kr.so.songjava.mvc.domain.entity.Board;
import kr.so.songjava.mvc.service.BoardSevice;
@RestController
@RequestMapping("/board")
@Api(tags="게시판 API")
public class BoardController {
@Autowired
private BoardSevice boardService;
/** 게시판 목록리턴 */
@GetMapping("/")
@ApiOperation(value="목록조회", notes="게시물 번호에 해당하는 목록정보를 조회할수 있습니다.")
public BaseResponse<List<Board>> getList(){
return new BaseResponse<List<Board>>(boardService.getList());
}
/** 게시판 상세보기 */
@GetMapping("/{boardSeq}")
@ApiOperation(value="상세조회", notes="게시물 번호에 해당하는 상세정보를 조회할수 있습니다.")
@ApiImplicitParams({
@ApiImplicitParam(name="boardSeq", value="게시물 번호", example = "1")
})
public BaseResponse<Board> get(@PathVariable int boardSeq) {
return new BaseResponse<Board>(boardService.get(boardSeq));
}
/** 게시판 등록/수정처리 */
@PutMapping("/save")
@ApiOperation(value="등록/수정처리", notes="신규 게시물 저장 및 기존 게시물 업데이트가 가능합니다.")
@ApiImplicitParams({
@ApiImplicitParam(name="boardSeq", value="게시물 번호", example = "1"),
@ApiImplicitParam(name="title", value="제목", example = "spring"),
@ApiImplicitParam(name="contents", value="내용", example="spring 강좌"),
})
public BaseResponse<Integer> save(BoardDto boardDto) {
boardService.save(boardDto);
return new BaseResponse<Integer>(boardDto.getBoardSeq());
}
/** 게시판 삭제처리 */
@DeleteMapping("/{boardSeq}")
@ApiOperation(value="게시판 삭제처리", notes="게시물 번호에 해당하는 정보를 삭제합니다.")
@ApiImplicitParams({
@ApiImplicitParam(name="boardSeq", value="게시물 번호", example = "1")
})
public BaseResponse<Boolean> delete(@PathVariable int boardSeq) {
return new BaseResponse<Boolean>(boardService.delete(boardSeq));
}
}
소스
https://github.com/stylehosting/example-spring
3. ControllerAdvice 사용과 예외처리 다국어 활용
다국어 참조
https://velog.io/@haerong22/Springboot-쿠키를-이용한-다국어-처리-i18n
1) 프러퍼티 설정
messages_en.properties
language = English
welcome = Hello, {0}
testName= My name is {0}. I live in {1}.
login.info.error= Login Error
user.password.hasLength= You must enter a password.
user.password.isTrue= Password does not match
messages_ko.properties
language = 한글
welcome = 안녕? {0}
testName= 제 이름은 {0} 입니다. 사는 곳은 {1} 입니다.
login.info.error= 로그인 오류
user.password.hasLength= 비밀번호를 필수로 입력해주셔야 합니다.
user.password.isTrue= 비밀번호가 일치하지 않습니다.
2) I18nConfig
import java.util.Locale;
import org.springframework.context.MessageSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ReloadableResourceBundleMessageSource;
import org.springframework.web.servlet.LocaleResolver;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.i18n.CookieLocaleResolver;
import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;
@Configuration
public class I18nConfig implements WebMvcConfigurer {
/** 스프링이 클라이언트의 언어,국가 정보를 인식하게 하는 메소드 여기서는 쿠키의 값을 저장하여 사용
*
* AcceptHeaderLocaleResolver : Http 헤더의 Accept-Language의 값을 사용한다. (기본값)
CookieLocaleResolver : 쿠키의 값을 저장하여 사용한다.
SessionLocaleResolver : 세션에 값을 저장하여 사용한다.
FixedLocaleResolver : 요청과 관계없이 default locale 사용한다.
* */
@Bean
public LocaleResolver localeResolver() {
CookieLocaleResolver resolver = new CookieLocaleResolver();
resolver.setDefaultLocale(Locale.getDefault());
resolver.setCookieName("lang");
return resolver;
}
/**
* Locale 값이 변경되면 인터셉터가 동작한다.
url의 query parameter에 지정한 값이 들어올 때 동작한다.
ex) http://localhost:8080?lang=ko
* @return
*/
@Bean
public LocaleChangeInterceptor localeChangeInterceptor() {
LocaleChangeInterceptor interceptor = new LocaleChangeInterceptor();
interceptor.setParamName("lang");
return interceptor;
}
/** 스프링이 작성한 언어 리소스들을 사용할 수 있게 등록,설정 */
@Bean
public MessageSource messageSource() {
// 지정한 시간마다 다시 리로드 하도록 한다.
ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
// 언어 리소스들이 있는 경로를 지정한다.
messageSource.setBasename("classpath:/i18n/messages");
messageSource.setDefaultEncoding("UTF-8"); // 인코딩
messageSource.setCacheSeconds(1); //개발시
//messageSource.setCacheSeconds(10 * 60); // 리로드 시간
messageSource.setDefaultLocale(Locale.KOREA);
messageSource.setUseCodeAsDefaultMessage(true);
return messageSource;
}
/**
* 인터셉터 등록
LocaleChangeInterceptor 를 스프링 컨테이너에 등록한다.
WebMvcConfigurer 를 상속받고 addInterceptors를 오버라이딩 한다.
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(localeChangeInterceptor());
}
}
3) GlobalControllerAdvice 설정
import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import kr.so.songjava.configuration.http.BaseResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
/**
* 예외 처리
* @RestControllerAdvice는 @ControllerAdvice+@ResponseBody의 역할을 한다.
* **/
@RestControllerAdvice
@RequiredArgsConstructor
@Slf4j
public class GlobalControllerAdvice {
private final MessageSource messageSource;
@ExceptionHandler(IllegalArgumentException.class)
public BaseResponse<?> handleIllegalArgumentException(IllegalArgumentException e){
String code=e.getMessage();
String message=messageSource.getMessage(code, null, LocaleContextHolder.getLocale());
log.info("code : {} ", code);
log.info("message : {} ", message);
log.info("e :{} ", e);
return new BaseResponse<Object>("error", null, message);
}
}
4)사용예 1
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import kr.so.songjava.mvc.domain.dto.UserDTO;
@RestController
@RequestMapping("/api/user")
public class UserApiController {
//비밀번호 예시 성공 값
private static final String DATABASE_PASSWORD ="test1234" ;
//@PostMapping("/confirm")
@GetMapping("/confirm") //get 테스트용
public ResponseEntity<UserDTO> confirm(@RequestParam String password){
Assert.hasLength(password, "user.password.hasLength");
Assert.isTrue(password.equals(DATABASE_PASSWORD) ,"user.password.isTrue");
UserDTO userDTO=new UserDTO();
userDTO.setUsername("개발자");
userDTO.setEmail("test@gmail.com");
return ResponseEntity.status(HttpStatus.OK).body(userDTO);
}
}
사용예2
import java.util.Locale;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
@Controller
@Api(tags="인덱스 API")
@Slf4j
public class IndexController {
@Autowired
private MessageSource messageSource;
@GetMapping({"","/"})
@ResponseBody
@ApiOperation(value="인덱스화면", notes="인덱스 홈 화면을 조회할수 있습니다.")
public String index(){
return "index";
}
@GetMapping("/i18n")
@ResponseBody
@ApiOperation(value="다국어테스트", notes="다국어테스트 입니다.")
@ApiImplicitParams({
@ApiImplicitParam(name="name", value="이름", example = "홍길동"),
@ApiImplicitParam(name="age", value="나이", example = "24"),
})
public String 다국어테스트(String name, String age){
log.info(messageSource.getMessage("welcome", new String[]{"kim"}, Locale.ENGLISH));
log.info(messageSource.getMessage("welcome", new String[]{"kim"}, Locale.KOREAN));
String code="login.info.error";
String message =messageSource.getMessage(code, null, LocaleContextHolder.getLocale());
log.info("message : {} " , message);
String message2=messageSource.getMessage("testName", new String[]{name ,age}, LocaleContextHolder.getLocale());
return message2;
}
}
소스
https://github.com/stylehosting/example-spring

















댓글 ( 4)
댓글 남기기