아키텍처와 함께

블로그 이미지
by gregorio
  • Total hit
  • Today hit
  • Yesterday hit

'분류 전체보기'에 해당되는 글 56건

  1. 2018.09.12
    Spring Framework Custom Annotation 만들기
  2. 2018.09.05
    Spring Batch Step간 데이터 공유
  3. 2018.09.04
    Spring framework AOP와 Annotaion을 이용한 Stop Watch 로그
  4. 2018.08.14
    [Spring Boot] JsonView 설정
  5. 2018.08.14
    [Spring Boot] Exception Resolver

Spring Framework에서는 다양한 Annotation을 제공하고 있으며, Annotation을 이용하여 XML을 사용하지 않고 Bean 설정, Property의 값을 읽을 수 있는 Annotation을 제공한다.


Annotation을 이용하여 SQL 수행 시 Binding 변수를 이용하여 SQL을 Log에 저장하는 Custom Annotation 예제이다.


SQL을 출력하기 위해서 Annotation과 AOP 기능을 이용하여 AOP 내에서 SQL 을 출력하도록 개발하였다.


먼저 Custom Annotation을 만든다.


■ BindSQL.java


import java.lang.annotation.Documented;

import java.lang.annotation.ElementType;

import java.lang.annotation.Retention;

import java.lang.annotation.RetentionPolicy;

import java.lang.annotation.Target;


@Documented

@Retention(RetentionPolicy.RUNTIME)

@Target(ElementType.METHOD)

public @interface BindSQL {


String[] sqlIds();

String paramType() default "";

}

 


BindSQL은 sqlIds와 paramType을 정의하고 있으며, sqlIds는 서비스에서 수행하는 Mybatis의 sqlId를 의미하며, paramType은 Mybatis의 해당 SQL의 paramterType이다.


BindSQL은 메소드 Level에 적용이 가능하며, Runtime 시점에 수행된다.


Method Level에서 수행되기 때문에 AOP를 적용한다.



■ AnnotationAspect.java


mport java.lang.reflect.Method;

import java.util.List;

import java.util.Map;


import javax.annotation.Resource;


import org.apache.ibatis.mapping.BoundSql;

import org.apache.ibatis.mapping.MappedStatement;

import org.apache.ibatis.mapping.ParameterMapping;

import org.apache.ibatis.mapping.ParameterMode;

import org.apache.ibatis.reflection.MetaObject;

import org.apache.ibatis.session.Configuration;

import org.apache.ibatis.session.SqlSessionFactory;

import org.apache.ibatis.type.JdbcType;

import org.apache.ibatis.type.TypeHandlerRegistry;

import org.aspectj.lang.JoinPoint;

import org.aspectj.lang.ProceedingJoinPoint;

import org.aspectj.lang.annotation.Around;

import org.aspectj.lang.annotation.Aspect;

import org.aspectj.lang.annotation.Before;

import org.aspectj.lang.reflect.MethodSignature;

import org.slf4j.Logger;

import org.springframework.context.annotation.EnableAspectJAutoProxy;

import org.springframework.core.annotation.Order;

import org.springframework.stereotype.Component;

import org.springframework.util.StopWatch;


import dymn.spring.annotation.BindSQL;

import dymn.spring.annotation.Logging;


@Aspect

@Component

@Order(2)

@EnableAspectJAutoProxy(proxyTargetClass=true)

public class AnnotationAspect {

@Resource(name = "sqlSessionFactory")

private SqlSessionFactory sqlSessionFactory;

@Around("@annotation(dymn.spring.annotation.StopWatch)")

private Object stopWatch(ProceedingJoinPoint joinPoint) throws Throwable {

StopWatch stopWatch = new StopWatch();

Object proceed = null;

String className = joinPoint.getSignature().getName();

try {

stopWatch.start();

proceed = joinPoint.proceed();

}

finally {

stopWatch.stop();

LOGGER.info("#{}({}): {} in {}[msec]s", className, joinPoint.getArgs(), proceed, stopWatch.getTotalTimeMillis());

}

return proceed;

}


@Before("@annotation(dymn.spring.annotation.BindSQL)")

public void bindingSql(JoinPoint joinPoint) throws Throwable {


/** Get annotation values **/

    MethodSignature signature = (MethodSignature) joinPoint.getSignature();

    Method method = signature.getMethod();


    BindSQL sqlAnnotation = method.getAnnotation(BindSQL.class);

    String[] sqlIds = sqlAnnotation.sqlIds();

    String paramType = sqlAnnotation.paramType();

    

    /** Get parameter for binding SQL **/

    Object sqlBindParam = null;

Object[] methodParams = joinPoint.getArgs();

if (!"".equals(paramType)) {

for (Object obj : methodParams) {

if ("Map".equals(paramType)) {

if (obj instanceof Map) {

sqlBindParam = obj;

break;

}

}

if ("String".equals(paramType)) {

if (obj instanceof String) {

sqlBindParam = obj;

break;

}

}

if ("int".equals(paramType)) {

if (obj instanceof Integer) {

sqlBindParam = obj;

break;

}

}

}

}

/** Binding SQL with parameter **/

for (String sqlId : sqlIds) {

Configuration configuration = sqlSessionFactory.getConfiguration();

MappedStatement statement = configuration.getMappedStatement(sqlId);

TypeHandlerRegistry typeHandlerRegistry = statement.getConfiguration().getTypeHandlerRegistry();

BoundSql boundSql = statement.getBoundSql(sqlBindParam);

String sql = boundSql.getSql().trim();


/** Binding SQL with parameter **/

List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();

if (parameterMappings != null) {

        for (int i = 0; i < parameterMappings.size(); i++) {

            ParameterMapping parameterMapping = parameterMappings.get(i);

            if (parameterMapping.getMode() != ParameterMode.OUT) {

                Object value;

                String propertyName = parameterMapping.getProperty();

                if (boundSql.hasAdditionalParameter(propertyName)) {

                    value = boundSql.getAdditionalParameter(propertyName);

                } else if (sqlBindParam == null) {

                    value = null;

                } else if (typeHandlerRegistry.hasTypeHandler(sqlBindParam.getClass())) {

                    value = sqlBindParam;

                } else {

                    MetaObject metaObject = configuration.newMetaObject(sqlBindParam);

                    value = metaObject.getValue(propertyName);

                }

                JdbcType jdbcType = parameterMapping.getJdbcType();

                if (value == null && jdbcType == null) {

                jdbcType = configuration.getJdbcTypeForNull();

                }

                sql = replaceParameter(sql, value, jdbcType, parameterMapping.getJavaType());

            }

        }

    }

LOGGER.info("Execute SQL :: [{}] :: [{}]", sql, sqlBindParam);

}

}

    private static String replaceParameter(String sql, Object value, JdbcType jdbcType, Class javaType) {

        String strValue = String.valueOf(value);

        if (jdbcType != null) {

            switch (jdbcType) {

                case BIT:

                case TINYINT:

                case SMALLINT:

                case INTEGER:

                case BIGINT:

                case FLOAT:

                case REAL:

                case DOUBLE:

                case NUMERIC:

                case DECIMAL:

                    break;

                case DATE:

                case TIME:

                case TIMESTAMP:

                default:

                    strValue = "'" + strValue + "'";

            }

        } else if (Number.class.isAssignableFrom(javaType)) {

        } else {

            strValue = "'" + strValue + "'";

        }

        

        return sql.replaceFirst("\\?", strValue);

    }

}

 


AnnotationAspect에서 @BindSQL Annoation을 사용한 Method가 실행하기 전에 bindSql Mehtod를 호출한다.


bindSql Method에서는 Annotation에서 정의한 sqlIds 값과 paramType 값을 찾는다.


SQL을 출력하기 위해 Mybatis의 MappedStatement에서 BoundSql Method에 입력된 Parameter를 이용하여 SQL을 생성한다.


SQL을 출력하면 SQL에 Bind 변수에 Parameter값이 Binding되어 있지 않기 때문에 replaceParamter Method를 호출하여 Binding을 한다.



서비스에서 @BindSQL Annotation을 사용한 예제이다.


  @BindSQL(sqlIds ={"deploy.target.selSystemNameList", "deploy.target.selSubSystemList"})

@StopWatch

public Map<String, Object> selCodeList() throws Exception {

Map<String, Object> resultMap = new HashMap<String, Object>();

List<Map<String, Object>> systemNameList = baseDao.selectList("deploy.target.selSystemNameList", null);

List<Map<String, Object>> subSystemList = baseDao.selectList("deploy.target.selSubSystemList", null);

resultMap.put("systemNameList", systemNameList);

resultMap.put("subSystemList", subSystemList);

return resultMap;

}


selCodeList Method에 @BindSQL sqlIds 값을 서비스에서 사용하는 sqlId 값을 정의한다.


Method Level의 Annotation은 AOP와 연계하여 다양한 Annotation을 작성할 수 있다.


일반적으로 Service와 ServiceImpl을 적용하여 서비스를 개발하는 경우에는 Service가 JoinPoint에서 수행되는 클래스는 Service로 Annotation이 동작하지 않는다.


이를 해결하기 위해  @EnableAspectJAutoProxy(proxyTargetClass=true) Annotation을 이용하면 해결이 가능하다.



AND

Spring Batch framework에서 하나의 Job에 여러개의 Step이 있을 경우 Step간에 데이터를 공유하는 방법이다.


먼저 Job에서 Step을 정의할 때 Spring Framework에서 제공하는  ExecutionContextPromotionListener를 각각의 Step의 Listener로 등록한다.


■ Job 정의 예제


<?xml version="1.0" encoding="UTF-8"?>

<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd

http://www.springframework.org/schema/batch http://www.springframework.org/schema/batch/spring-batch.xsd">

<import resource="classpath:/spring/context-main.xml" />


<!-- Send Data between steps -->

<bean id="promotionListener" class="org.springframework.batch.core.listener.ExecutionContextPromotionListener">

<property name="keys" value="params" />

</bean>

<job id="BatchApiKeyResetJob" parent="baseJob" xmlns="http://www.springframework.org/schema/batch">

<step id="BatchApiKeyResetJobStep1">

<tasklet>

<chunk reader="BatchApiKeyResetJobStepReader" processor="BatchApiKeyResetJobStepProcessor" writer="BatchApiKeyResetJobStepWriter" commit-interval="10"></chunk>

<listeners>

<!-- listener ref="apiKeyResultJobStepListener" /-->

<listener ref="promotionListener" />

</listeners>

</tasklet>

<next on="*" to="BatchApiKeyResetJobStep2"/>

</step>

<step id="BatchApiKeyResetJobStep2" parent="BatchApiKeyResetJobStep1">

<tasklet>

<chunk reader="BatchApiKeyResetJobStepReader" processor="BatchApiKeyResetJobStepProcessor2" writer="BatchApiKeyResetJobStepWriter" commit-interval="10"></chunk>

<listeners>

<!-- listener ref="apiKeyResultJobStepListener" /-->

<listener ref="promotionListener" />

</listeners>

</tasklet>

</step>

</job>

<!-- Reader Setting -->

<bean id="BatchApiKeyResetJobStepReader" class="org.mybatis.spring.batch.MyBatisPagingItemReader" scope="step">

<property name="queryId" value="common.BatchInterface_SQL.retrieveInterfaceList" />

<property name="sqlSessionFactory" ref="sqlSession" />

</bean>

<!-- Processor Setting -->

<bean id="BatchApiKeyResetJobStepProcessor" class="batch.processor.BatchApiKeyResetJobProcessor" >

<property name="baseDao" ref="durBaseDao" />

</bean>

<!-- Processor Setting -->

<bean id="BatchApiKeyResetJobStepProcessor2" class="batch.processor.BatchApiKeyResetJobProcessor2" >

<property name="baseDao" ref="durBaseDao" />

</bean>


<!-- Writer Setting -->

<bean id="BatchApiKeyResetJobStepWriter" class="org.mybatis.spring.batch.MyBatisBatchItemWriter" scope="step">

<property name="statementId" value="common.BatchInterface_SQL.updateInterface" />

<property name="sqlSessionFactory" ref="sqlSession" />

<property name="assertUpdates" value="false" />

</bean>

</beans>


각 Step간에 전달할 keys를 정의한다. 여기서는 하나의 객체만 전달하기 때문에 params로 값을 정의하였다.


ItemProcess에서 StepExecution을 이용하여 params를 이용하여 값을 저장한다.


■BatchApiKeyResetJobProcessor.java


import javax.annotation.Resource;


import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.batch.core.ExitStatus;

import org.springframework.batch.core.StepExecution;

import org.springframework.batch.core.annotation.AfterStep;

import org.springframework.batch.core.annotation.BeforeStep;

import org.springframework.batch.item.ExecutionContext;


import cmn.util.dao.CamelMap;


public class BatchApiKeyResetJobProcessor extends BaseProcessor<CamelMap, CamelMap> {

private static final Logger LOGGER = LoggerFactory.getLogger(BatchApiKeyResetJobProcessor.class);

@Resource(name="testService")

private TestService testService;

private StepExecution stepExecution;

@Override

public CamelMap executeProcess(CamelMap camelMap) throws Exception {

if (LOGGER.isDebugEnabled()) {

LOGGER.debug("Input Data :: {}", camelMap);

}

// baseDao.update("sehati.common.BatchInterface_SQL.testupdate1", camelMap);

String uuid = UUID.randomUUID().toString().toUpperCase().replaceAll("-", "");

camelMap.put("intfAuthCrtfId", uuid);

stepExecution.getExecutionContext().put("uuid", uuid);

ExecutionContext stepContext = this.stepExecution.getExecutionContext();

stepContext.put("params", camelMap);

return camelMap;

}

@BeforeStep

public void beforeStep(StepExecution stepExecution) {

this.stepExecution = stepExecution;

}

@AfterStep

public ExitStatus afterStep(StepExecution stepExecution) {

String uuid = stepExecution.getExecutionContext().getString("uuid");

LOGGER.debug("UUID :: {}", uuid);

ExitStatus exitStatus = stepExecution.getExitStatus();

if( exitStatus.getExitCode() != ExitStatus.COMPLETED.getExitCode()) {

try {

testService.updateData(new CamelMap());

} catch (Exception e) {

e.printStackTrace();

}

}

return exitStatus;

}


}


먼저 Step이 실행되기 전에 stepExecution을 ItemProcessor에 정의되어 있는 stepExecution 변수에 저장한다.


ItemProcessor에서 stepException를 이용하여 stepContext를 객체를 생성한 후   promotionListener Bean에서 정의한 keys의 value를 이용하여 stepContext에 다음 Step에 전달할 데이터를 저장한다.



■BatchApiKeyResetJobProcessor2.java


import java.util.UUID;


import javax.annotation.Resource;


import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.batch.core.ExitStatus;

import org.springframework.batch.core.JobExecution;

import org.springframework.batch.core.StepExecution;

import org.springframework.batch.core.annotation.AfterStep;

import org.springframework.batch.core.annotation.BeforeStep;

import org.springframework.batch.item.ExecutionContext;


import cmn.util.dao.CamelMap;

import cmn.util.spring.batch.processor.BaseProcessor;

import sehati.batch.service.TestService;


public class BatchApiKeyResetJobProcessor2 extends BaseProcessor<CamelMap, CamelMap> {

private static final Logger LOGGER = LoggerFactory.getLogger(BatchApiKeyResetJobProcessor2.class);

@Resource(name="testService")

private TestService testService;

private StepExecution stepExecution;

@Override

public CamelMap executeProcess(CamelMap camelMap) throws Exception {

if (LOGGER.isDebugEnabled()) {

LOGGER.debug("Input Data :: {}", camelMap);

}

baseDao.update("sehati.common.BatchInterface_SQL.testupdate1", camelMap);

String uuid = UUID.randomUUID().toString().toUpperCase().replaceAll("-", "");

camelMap.put("intfAuthCrtfId", uuid);

stepExecution.getExecutionContext().put("uuid", uuid);

ExecutionContext stepContext = this.stepExecution.getExecutionContext();

stepContext.put("params", camelMap);


return camelMap;

}

@BeforeStep

public void beforeStep(StepExecution stepExecution) {

JobExecution jobExecution = stepExecution.getJobExecution();

ExecutionContext jobContext = jobExecution.getExecutionContext();

CamelMap camelMap = (CamelMap) jobContext.get("params");

LOGGER.info("{}", camelMap);

this.stepExecution = stepExecution; 

}

@AfterStep

public ExitStatus afterStep(StepExecution stepExecution) {

if( stepExecution.getExitStatus().getExitCode() != ExitStatus.COMPLETED.getExitCode()) {

try {

testService.updateData(new CamelMap());

} catch (Exception e) {

e.printStackTrace();

}

}

return stepExecution.getExitStatus();

}


}


ItemProcess에서 Step이 실행되기 전에 이전 Step에서 stepContext에 저장한 객체를 받아온다.


이렇게 하면 Step간에 데이터를 공유할 수 있다.


물론 실 환경에 적용하기 위해서는 더 많은 고민이 필요할 거 같다.

예를 들면 Chunked 방식으로 하는 경우 Step간에 공유할 데이터를 어디에서 생성할 것인지 또는 AfterStep에서 하는 경우 ItemProcess에서 AfterStep에 데이터를 보내는 방법 등 해결해야할 이슈가 있다.


물론 예제를 보면 ItemProcess에서 setpExecution에서 객체를 저장하는 방법이 있다.

AND

Spring Framework에서 AOP와 Annotation을 이용하여 Elapsed time을 Log에 생성하는 예제이다.


먼저 StopWatch Annotation 생성한다.


■ StopWatch.java


import java.lang.annotation.Documented;

import java.lang.annotation.ElementType;

import java.lang.annotation.Retention;

import java.lang.annotation.RetentionPolicy;

import java.lang.annotation.Target;


@Documented

@Retention(RetentionPolicy.RUNTIME)

@Target({ElementType.METHOD})

public @interface StopWatch {

}



StopWatch Annotation은 Method Level에 적용하기 때문에 @Target을 METHOD로 정의하였으며, Runtime시에 적용한다.



다음은 메소드의 수행시간을 로그에 기록하기 위해 AOP 생성한다.


■ LoggingAspect.java


import org.aspectj.lang.ProceedingJoinPoint;

import org.aspectj.lang.annotation.Around;

import org.aspectj.lang.annotation.Aspect;

import org.aspectj.lang.annotation.Pointcut;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.stereotype.Component;

import org.springframework.util.StopWatch;


@Aspect

@Component

public class LoggingAspect {


@Around("@annotation(sehati.bi.annotation.StopWatch)")

public Object stopWatch(ProceedingJoinPoint joinPoint) throws Throwable {

StopWatch stopWatch = new StopWatch();

Object proceed = null;

String className = joinPoint.getSignature().getName();

try {

stopWatch.start();

proceed = joinPoint.proceed();

}

finally {

stopWatch.stop();

LOGGER.info("{} elapsed time :: {}", className, stopWatch.getTotalTimeMillis());

}

return proceed;

}


}




@Aspect Annotation을 이용하여 AOP 를 구현한다.

@Around Advice을 적용 시 Point Cut을 StopWatch Annotation을 사용한 모든 Method는 stopWatch 메소드에 의해 호출된다.



다음은 @StopWatch Annotation 적용 예제이다.


  @RequestMapping(value = "/bi/mainpage.do")

@StopWatch

public String mainPageView(HttpServletRequest request) throws Exception {

LOGGER.info("Called :: {}", request.getRequestURL());

return "main";

}


mainPageView를 @StopWatch Annotation을 적용해 로그에 Elasped time이 기록된다.


AND

Spring Boot에서 JsonView를 bean으로 설정하는 방법이다.


Spring MVC에서는 View를 정의하기 위해 XMLViewResolver를 사용하여 bean의 위치를 정의하고, View 정의하는 파일에 JsonView를 설정한다.



■ mvc-servlet-context.xml

  <!-- Set XML View Resolver -->

<bean class="org.springframework.web.servlet.view.XmlViewResolver">

<property name="location" value="classpath:spring/context-views.xml"/>

<property name="order" value="1" />

</bean>



■ context-views.xml


<bean id="jsonView" class="org.springframework.web.servlet.view.json.MappingJackson2JsonView" /> 


위와 같이 정의한 후 ModelAndView를 사용 시 setViewName 메소드에 Parameter로 jsonView를 정의하면 데이터를 JSON으로 변환하여 클라이언트에 전송한다.



Spring Boot에서는 XML을 사용하지 않을 경우에는 MappingJackson2JsonView를 bean으로 정의하면 사용할 수 있다.



■ WebConfg.java


import java.util.ArrayList;

import java.util.List;

import java.util.Locale;


import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.boot.web.servlet.FilterRegistrationBean;

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

import org.springframework.context.support.ReloadableResourceBundleMessageSource;

import org.springframework.core.Ordered;

import org.springframework.web.servlet.LocaleResolver;

import org.springframework.web.servlet.config.annotation.InterceptorRegistry;

import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;

import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;

import org.springframework.web.servlet.i18n.SessionLocaleResolver;

import org.springframework.web.servlet.view.json.MappingJackson2JsonView;


import dymn.demo.filter.ABCFilter;

import dymn.demo.interceptor.SessionInterceptor;

import dymn.demo.util.PropertiesUtil;


@Configuration

public class WebConfig implements WebMvcConfigurer {

@Bean

public MappingJackson2JsonView jsonView() {

return new MappingJackson2JsonView();

}

}





AND

Spring Boot 사용 시 Exception이 발생하면 Exception을 사용자에게 보내기 위해 SimpleMappingExceptionResolver를 상속받아 Exception을 처리할 수 있다.



SimpleMappingExceptionResolver를 상속받으면 doResolveException 메소드를 재정의하여 Exception 발생 시 메세지를 JSON Format으로 클라이언트에게 전달한다.


doResolverException 메소드에서 Exception의 Type에 따라 메세지를 처리할 수 있다.


Spring Boot에서는 해당 Class를 Component Annotation을 이용하여 bean으로 설정한다.


■JsonExceptionResolver.java


import java.util.HashMap;

import java.util.Map;

import java.util.regex.Matcher;

import java.util.regex.Pattern;


import javax.servlet.http.HttpServletRequest;

import javax.servlet.http.HttpServletResponse;


import org.apache.ibatis.exceptions.PersistenceException;

import org.mybatis.spring.MyBatisSystemException;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.dao.DataAccessException;

import org.springframework.stereotype.Component;

import org.springframework.web.servlet.ModelAndView;

import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;


import dymn.demo.base.BaseConstants;

import dymn.demo.util.MessageUtil;

import dymn.demo.util.NullUtil;


//@Configuration


/** This class should used @Component annotation */

/** If you want to declare as a bean, create bean in WebConfig class **/

@Component

public class JsonExceptionResolver extends SimpleMappingExceptionResolver {

private static final Logger LOGGER = LoggerFactory.getLogger(JsonExceptionResolver.class);

    private final  String exceptionCodeAttribute = "exception";


@Override

    protected ModelAndView getModelAndView(String viewName, Exception ex) {

ModelAndView mv = super.getModelAndView(viewName,ex);

Map<String, Object> model = mv.getModel();

String code = model.get(this.exceptionCodeAttribute)!=null ?

        (String)model.get(this.exceptionCodeAttribute):  BaseConstants.DEFAULT_ERROR_CODE;

       

        String message = ex.getMessage();

        try {

            message = message == null ? MessageUtil.getMessage(code) : message;       

        }

        catch(Exception exception) {

        message = "";

        }


        model.put("message", message);

        model.put("error", "true");

        model.put("errortype", ex.getClass().getSimpleName());

        model.put("code",code);


return mv;

    }

 

    @Override

    protected ModelAndView doResolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {

    String msgCode = null;

    String msgValue = null;

   

    ex.printStackTrace();

 

    if (ex instanceof BizException) {

    BaseException be = (BaseException)ex; 

    msgCode = be.getCode();

    msgValue = be.getMessage();

    if (msgValue == null) {

            try {

              msgValue = MessageUtil.getMessage(msgCode);

              msgValue = msgCode + "<BR>" + msgValue; 

            }

            catch(Exception exception) {

              msgValue = "";

            }   

    }

    }

    /** Mybatis Or Database Exception **/

    else if (ex instanceof MyBatisSystemException || ex instanceof PersistenceException || ex instanceof DataAccessException ) {

    msgCode = BaseConstants.DEFAULT_DB_ERROR_CODE;

   

    if (ex.getCause() instanceof java.sql.SQLException) {

        /*-------------------------------------------------------------

        * 오라클의 경우 모든 오류를 SQLException으로 날립니다.

        * 이에 해당 오류메세지를 구분하여 메세지를 설정해야합니다.

        * 민자영업소의 요청에 따라 Oracle Exception ID 정보를 출력합니다.

        *-------------------------------------------------------------*/

        msgCode = BaseConstants.DEFAULT_DB_ERROR_CODE;

        String oraErrMsg = ex.getCause().getMessage();

       

        // 오라클 오류메세지 여부를 판단합니다.

        if (oraErrMsg != null && oraErrMsg.length() > 0) {

        String oraCode = null;

        Pattern pattern = Pattern.compile("ORA-\\d+");

       

        Matcher matcher = pattern.matcher(oraErrMsg);

       

        if (matcher.find()) {

        oraCode = matcher.group();

        }

        try {

        msgValue = MessageUtil.getMessage( msgCode, new Object[] {oraCode});

        msgValue = msgCode + "<BR>" + msgValue;

        }

        catch(Exception exception) {

        msgValue = "";

        }

        }

    }

    else {

    try {

    msgValue = MessageUtil.getMessage( msgCode);

    msgValue = msgCode + "<BR>" + msgValue;

    }

    catch(Exception exception) {

    msgValue = "";

    }       

    }

       

    }

    else {

    /** Set Default Message Code **/

    msgCode =  BaseConstants.DEFAULT_ERROR_CODE;

            try {

            msgValue = MessageUtil.getMessage( msgCode);

            msgValue = msgCode + "<BR>" + msgValue; 

            }

            catch(Exception exception) {

            msgValue = "";

            } 

    }

   


    /** Set error code and message for client **/

        Map<String, Object> retMsg = new HashMap<String, Object>();

        

      retMsg.put("message", msgValue);

      msgCode = !NullUtil.isNone(msgCode) ? msgCode : BaseConstants.DEFAULT_ERROR_CODE;

        retMsg.put("status", BaseConstants.STATUS_ERROR);


        if (LOGGER.isDebugEnabled()) {

            LOGGER.debug("Error Message to clinet :: {}", retMsg.toString());       

        }

       

       ModelAndView mav = new ModelAndView();

       mav.setViewName("jsonView");


       mav.addObject("message", retMsg);

       return mav;

    }

}

 



Exception에 에러코드만 있는 경우에는 메세지 파일에 정의되어 있는 메세지를 읽어서 JSON으로 생성하고, 에러코드와 메세지가 있는 경우 오류 코드와 메세지를 Json형식으로 만들어 화면에 전달한다.


Spring MVC에서는 mvc-servlet-context.xml에 bean으로 정의하면 된다.


  <!-- Exception Resolver -->

<bean id="exceptionResolver" class="cmn.deploy.exception.JsonExceptionResolver">

<property name="maxLength" value="1000" />

</bean>


AND

ARTICLE CATEGORY

분류 전체보기 (56)
Spring Framrwork (33)
Linux (1)
APM (1)
Java (8)
python (0)
ant (1)
chart (1)
OS (1)
tomcat (1)
apache (1)
database (0)

RECENT ARTICLE

RECENT COMMENT

CALENDAR

«   2024/10   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31

ARCHIVE

LINK