@ControllerAdvice+@ResponseBody 를 한꺼번에 사용 할 수 있게 해주는 어노테이션 입니다.

 

@ControllerAdvice은 @InitBinder, @ModelAttribute, @ExceptionHandler 관련 어노테이션을 여러 컨트롤러에 걸쳐 공통으로 설정 할 수 있게 해주는 어노테이션 인데 ExceptionHandler를 위해서 많이 사용 하고 있습니다.

 

@ControllerAdvice(assignableTypes={TestController.class, Test2Controller.class})

와 같이 사용해서 영향을 미치는 컨트롤러를 정의 할 수 있고 범위는 class, 패키지, 특정 어노테이션 등으로 정의 할 수 있습니다.

assignableTypes의 조건을 많이 사용하는 경우 성능에 악영향을 미칠 수 있습니다.

https://docs.spring.io/spring-framework/docs/5.3.18/javadoc-api/org/springframework/web/bind/annotation/ControllerAdvice.html

 

ControllerAdvice (Spring Framework 5.3.18 API)

Specialization of @Component for classes that declare @ExceptionHandler, @InitBinder, or @ModelAttribute methods to be shared across multiple @Controller classes. Classes annotated with @ControllerAdvice can be declared explicitly as Spring beans or auto-d

docs.spring.io

ExceptionHandler 와 같이 사용하는 경우 아래와 같이 사용 할 수 있습니다.

@RestControllerAdvice
public class ControllerExceptionHandler {
	private Logger logger = LoggerFactory.getLogger(this.getClass());
	
	@ResponseStatus(value = HttpStatus.OK)
	@ExceptionHandler(value = NullPointerException.class)
    public HashMap<String, Object> nullPointerException(Exception e, Model model) {
		
		logger.error(e.getLocalizedMessage());
		
		HashMap<String, Object> returnMap = new HashMap<String, Object>();
		returnMap.put("result", false);
		returnMap.put("message", "비정상적인 정보(null) 입니다.");
		
        return returnMap;
    }
    
    @ResponseStatus(value = HttpStatus.OK)
	@ExceptionHandler(value = ClassCastException.class)
    public HashMap<String, Object> classCastException(Exception e, Model model) {
		
		logger.error(e.getLocalizedMessage());
		
		HashMap<String, Object> returnMap = new HashMap<String, Object>();
		returnMap.put("result", false);
		returnMap.put("message", "프로그램이 비정상 구동 되었습니다. 시스템 확인이 필요 합니다.(classCastException)");
		
        return returnMap;
    }
    
    @ResponseStatus(value = HttpStatus.OK)
   	@ExceptionHandler(value = NoClassDefFoundError.class)
       public HashMap<String, Object> noClassDefFoundError(Exception e, Model model) {
   		
   		logger.error(e.getLocalizedMessage());
   		
   		HashMap<String, Object> returnMap = new HashMap<String, Object>();
   		returnMap.put("result", false);
   		returnMap.put("message", "프로그램이 비정상 구동 되었습니다. 시스템 확인이 필요 합니다.(noClassDefFoundError)");
   		
           return returnMap;
       }
	
	@ResponseStatus(value = HttpStatus.OK)
	@ExceptionHandler(value = ArrayIndexOutOfBoundsException.class)
    public HashMap<String, Object> arrayIndexOutOfBoundsException(Exception e, Model model) {
		
		logger.error(e.getLocalizedMessage());
		
		HashMap<String, Object> returnMap = new HashMap<String, Object>();
		returnMap.put("result", false);
		returnMap.put("message", "비정상적인 배열 정보 입니다.(ArrayIndexOutOfBoundsException)");
		
        return returnMap;
    }
	
	@ResponseStatus(value = HttpStatus.OK)
	@ExceptionHandler(value = IndexOutOfBoundsException.class)
    public HashMap<String, Object> indexOutOfBoundsException(Exception e, Model model) {
		
		logger.error(e.getLocalizedMessage());
		
		HashMap<String, Object> returnMap = new HashMap<String, Object>();
		returnMap.put("result", false);
		returnMap.put("message", "비정상적인 배열 정보를 확인 하고 있습니다.(IndexOutOfBoundsException)");
		
        return returnMap;
    }
	
	@ResponseStatus(value = HttpStatus.OK)
	@ExceptionHandler(value = ClassNotFoundException.class)
    public HashMap<String, Object> classNotFoundException(Exception e, Model model) {
		
		logger.error(e.getLocalizedMessage());
		
		HashMap<String, Object> returnMap = new HashMap<String, Object>();
		returnMap.put("result", false);
		returnMap.put("message", "프로그램이 비정상 구동 되었습니다. 시스템 확인이 필요 합니다.(ClassNotFoundException)");
		
        return returnMap;
    }
	
	@ResponseStatus(value = HttpStatus.OK)
	@ExceptionHandler(value = PersistenceException.class)
    public HashMap<String, Object> persistenceException(Exception e, Model model) {
		
		logger.error(e.getLocalizedMessage());
		
		HashMap<String, Object> returnMap = new HashMap<String, Object>();
		returnMap.put("result", false);
		returnMap.put("message", "데이터 작업 중 문제가 발생 되었습니다.");
		
        return returnMap;
    }
	
}

service 및 repository 에서는 모든 예외를 throws 하고 ControllerAdvice를 이용해서 조건에 맞는 에러에 대한

응답을 json으로 사용자 화면에 출력 합니다.

이때 @ResponseStatus(value = HttpStatus.OK) 코드로 정상 응답이 된걸로 변경 해줍니다.

 

https://docs.spring.io/spring-framework/docs/current/reference/html/web.html#mvc-ann-controller-advice

 

Web on Servlet Stack

This part of the reference documentation covers support for Servlet stack, WebSocket messaging that includes raw WebSocket interactions, WebSocket emulation through SockJS, and publish-subscribe messaging through STOMP as a sub-protocol over WebSocket. 4.1

docs.spring.io

 

반응형
Posted by 질주하는구
,

html에서는 사용자 정의 attribute를 사용 할 수 있게 data- 라는 속성을 제공 하고 있습니다.

명명 규칙은 data- 로 시작 해야 한다는 점을 빼고는 사용자가 원하는 데이터를 제한 없이 정의 할 수 있습니다.

사용 방법은 아래와 같습니다.

<article
  id="electriccars"
  data-columns="3"
  data-index-number="12314"
  data-parent="cars">
...
</article>

javascript에서 해당 정보를 가지고 오려는 경우 아래와 같이 간단한 방식으로 접근 가능 합니다.

var article = document.getElementById('electriccars');

article.dataset.columns // "3"
article.dataset.indexNumber // "12314"
article.dataset.parent // "cars"

dataset을 이용해서 접근 하고 접근시 data- 이후의 내용을 key로 접근 하게 됩니다.

jQuery로 접근 하는 경우 아래와 같이 접근 가능 합니다.

$("#electriccars").attr("data-columns");
$("#electriccars").attr("data-index-number");
$("#electriccars").attr("data-parent");

해당 내용은 html의 속성으로 존재 하기 때문에 CSS에서도 해당 정보에 접근 할 수 있습니다.

article[data-columns='3'] {
  width: 400px;
}
article[data-columns='4'] {
  width: 600px;
}

현재 프론트 개발의 경우 많은 부분 react 나 vue.js를 사용하기 때문에 상기와 같은 html 속성을 사용할 일이 없을 수 있습니다.

하지만 저 같이 html+jquery+Vanilla JS+bootstrap 을 이용해서 작업하는 분들의 경우 유용하게 사용 할 수 있을거 같습니다.

관심 있는 내용인 경우 아래의 url 정보를 간략하게 정리한 내용이라 url을 참고 하시면 됩니다.

https://developer.mozilla.org/ko/docs/Learn/HTML/Howto/Use_data_attributes

 

데이터 속성 사용하기 - Web 개발 학습하기 | MDN

HTML5 특정 요소와 연관되어 있지만 확정된 의미는 갖지 않는 데이터에 대한 확장 가능성을 염두에 두고 디자인되었습니다. data-* 속성은 표준이 아닌 속성이나 추가적인 DOM 속성, Node.setUserData

developer.mozilla.org

https://www.w3schools.com/tags/att_data-.asp

 

HTML data-* Attribute

W3Schools offers free online tutorials, references and exercises in all the major languages of the web. Covering popular subjects like HTML, CSS, JavaScript, Python, SQL, Java, and many, many more.

www.w3schools.com

 

반응형

'HTML' 카테고리의 다른 글

사이트, 페이지 설명 meta태그 추가  (0) 2021.06.29
html5 file drag and drop  (0) 2021.05.14
페이스북 로그인 연동(javascript api)  (0) 2016.03.01
object 태그를 이용한 pdf보여주기  (0) 2015.09.21
fckeditor2.6 IE9문제  (0) 2015.03.09
Posted by 질주하는구
,

spring boot 에 view template으로 freemarker을 적용하는 간단한 방법을 정리 합니다.

 

spring boot 에서는 view templat으로 (FreeMarker, Groovy, Thymeleaf, Mustache) 을 지원하고 있습니다.

이중 spring에서는 Thymeleaf를 적극적으로 지원 하고 있고 해당 탬플릿의 경우 커스텀 유연성이 높아 많은 사용자가

사용하고 있습니다.

Groovy나 Mustache의 경우 사용 속도, 사용방법, 커뮤니티 활성화 등 다른 2개의 템플릿보다 떨어지는 부분이

많아 spring boot에서 view template을 사용한다면 freemarker 이나 Thymeleaf를 사용하는게 좋습니다.

 

2개의 템플릿중 freemarker 를 적용하는 방법을 간단하게 기술 합니다.

(토이프로젝트로 폼빌더 관련 작업시 view template으로 freemarker을 사용할 예정 이여서 관련 내용을 적용하면서 정리

하는 겁니다. 해당 템플릿을 선택한 이유는 커스텀을 거의 사용하지 않을것이고 충분한 속도, jstl과 크게 차이나지 않는 사용 방법 및 사용관련 내용이 잘 정리 되어 있어 freemarker을 선택 했습니다.)

 

먼저 build.gradle에 의존성을 추가 해줍니다.

implementation 'org.springframework.boot:spring-boot-starter-freemarker'

그뒤 freemarker에서 사용할 설정 내용을 application.properties에 추가 해줍니다.

#freemarker 템플릿 경로 지정
spring.freemarker.template-loader-path=classpath:/templates 
#return 호출시 앞쪽에 자동으로 붙는 내용 정의
spring.freemarker.prefix=/freemarker
#return 호출시 뒷쪽에 자동으로 붙는 내용 정의
spring.freemarker.suffix=.ftl
#freemarker content type 정의
spring.freemarker.contentType=text/html
#freemarker charset 정의
spring.freemarker.charset=UTF-8
#기본은 true (false로 설정 하는 경우 프리마커 변경 내용이 바로 적용 됨) 
spring.freemarker.cache=false

위의 내용을 추가 해주면 모든 준비가 되었습니다. 서비스 시작시 호출할 ftl파일을

설저한 /src/main/resources/templates/freemarker 폴더 하위로 생성 해주고 호출 해주면 됩니다.

 

저는 bootstrap을 사용할 예정이여서 layout.ftl 파일을 만들고 해당 파일을 호출 하면서 실제 동작하는 내용에 해당하는

list.ftl을 <#include incPath> 으로 호출 하려고 합니다.

 

modelAndView.addObject("incPath", "../formSet/list.ftl");
modelAndView.setViewName("/layout/layout_view_1");

으로 경로를 정의 해주고 해당 파일을 

/src/main/resources/templates/freemarker/layout/layout.ftl
/src/main/resources/templates/freemarker/formSet/list.ftl

에 만들어 주면 작업한 화면을 볼 수 있습니다.

 

incPath의 경로를 ../formSet/list.ftl 으로 지정 해줘야(파일의 실제 경로) include 할 수 있습니다.

반응형
Posted by 질주하는구
,