SSO 처리를 위해 AbstractAuthenticationProcessingFilter를 사용하여 사전에 사용자 정보를 가져와 로그인 처리를 하려 하는데 분명 로그인을 했는데 자꾸 AnonymousUser라고 로그인 안 된거 처럼 되는 현상으로 하루 죙일 구글링 시작...

찾은 결과

SecurityContext는 인증 성공후에 기본적으로 저장하지 않는다. 
UsernamePasswordAuthenticationFilter는 form-login 기반으로 SSO 처리시에는 호출 되지 않기 때문에
SessionManagementFilter에 인증정보를 감지할 수 없다.
그렇기 때문에 인증 성공후에 인정된 객체를 SecurityContext에 저장해야 한다.
SecurityContext에 저장하기 위하여는 AbstractAuthenticationProcessingFilter의 successfulAuthentication를 재정의하여야 한다.

@Override
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {

        SecurityContext context = SecurityContextHolder.createEmptyContext();
        context.setAuthentication(authResult);
        //SecurityContextHolder.setContext(context);
        HttpSessionSecurityContextRepository secRepo = new HttpSessionSecurityContextRepository();
        secRepo.saveContext(context, request, response);

        super.successfulAuthentication(request, response, chain, authResult);
}

이걸 찾는데 너무 오랜 시간을 사용했다...ㅜㅜ

SecurityConfig에서 해당 부분만 발췌한 내용은 아래와 같다.

@Configuration
@EnableWebSecurity
public class SpringSecurityConfig {

    ...
    
    @Autowired
    private UrlBasedAuthorizationManager urlBasedAuthorizationManager;

    @Bean
    public PasswordEncoder encoder() {
    return new BCryptPasswordEncoder();
    }

    @Bean
    protected SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    	http
			.csrf((csrf) ->
				csrf.disable()
			)
            .authorizeHttpRequests(
					(requests) ->
							requests
								.requestMatchers("/", "/loginionvalid.html").permitAll()
								.anyRequest().authenticated()
			)
			.formLogin((form) ->
							form
								.loginPage("/login.html")
								.usernameParameter("userId")
								.passwordParameter("pass")
								.loginProcessingUrl("/login/proc.html")
								.defaultSuccessUrl("/")
								.successHandler(customAuthenticationSuccessHandler)
								.failureHandler(customAuthenticationFailureHandler)
								.permitAll()
			)
			.logout((logout) ->
						logout
							.logoutUrl("/logout.html")
							//.logoutSuccessHandler(null)
							.logoutSuccessUrl("/")
							.permitAll()
			)
			.addFilterBefore(requestProcessingFilter(http), UsernamePasswordAuthenticationFilter.class)
			.addFilterBefore(urlBaseAuthorizationFilter(), AuthorizationFilter.class)
		;

        return http.build();
    }
    
    /**
     * SSO 처리를 위한 처리
     * @param http
     * @return
     * @throws Exception
     */
    @Bean
    public RequestProcessingFilter requestProcessingFilter(HttpSecurity http) throws Exception {

        AuthenticationManager authenticationManager = http.getSharedObject(AuthenticationManagerBuilder.class).build();

        RequestProcessingFilter rpf = new RequestProcessingFilter("/ssoLogin.html");
        rpf.setAuthenticationManager(authenticationManager);
        rpf.setAuthenticationFailureHandler(ssoAuthenticationFailureHandler);
        rpf.setAuthenticationSuccessHandler(customAuthenticationSuccessHandler);
        return rpf;
    }
    
    ...
}


RequestProcessingFilter.java

public class RequestProcessingFilter extends AbstractAuthenticationProcessingFilter {

	private String usernameParameter = "userInfo";

	public RequestProcessingFilter(String defaultFilterProcessesUrl) {
		super(defaultFilterProcessesUrl);
	}

	@Override
	public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
			throws AuthenticationException, IOException, ServletException {

		String requestInfo = obtainUsername(request);
		if( !StringUtils.hasText(requestInfo) ) {
			logger.error("사용자 정보 연계시 사용자 정보 미전송");
			throw new BadCredentialsException("사용자 정보가 올바르게 전송되지 않았습니다. 관리자에게 문의하여 주시기 바랍니다.");
		}

		...
		String userNo = ...;

		UsernamePasswordAuthenticationToken authRequest = UsernamePasswordAuthenticationToken.unauthenticated(userNo,
				"user1");

		// Allow subclasses to set the "details" property
		setDetails(request, authRequest);
		return this.getAuthenticationManager().authenticate(authRequest);
	}

	protected void setDetails(HttpServletRequest request, UsernamePasswordAuthenticationToken authRequest) {
		authRequest.setDetails(this.authenticationDetailsSource.buildDetails(request));
	}

	public String obtainUsername(HttpServletRequest request){
		return request.getParameter(usernameParameter);
	}

	@Override
	protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {

	        SecurityContext context = SecurityContextHolder.createEmptyContext();
	        context.setAuthentication(authResult);
	        //SecurityContextHolder.setContext(context);
	        HttpSessionSecurityContextRepository secRepo = new HttpSessionSecurityContextRepository();
	        secRepo.saveContext(context, request, response);

	        super.successfulAuthentication(request, response, chain, authResult);
	}

}

Eclipse IDE 2020‑03 을 다운받아 사용하려는데 Market에 PropertiesEditor이 없다..ㅡㅡ;;;;;

예전 것은 있으나 지원이 안된다고 한다..

그래서 결론은 수동으로 처리 해야 함.


다운로드 URL : http://propedit.sourceforge.jp/eclipse/updates 

여기서 PropertiesEditor 만 설치 하면 됨.

이거 검색하는게 왜케 힘든지..ㅡㅡ;;

그래서 등록...ㅋ


public static Map<String, Object> loadFile(String path) throws IOException {

    ByteArrayOutputStream baos = new ByteArrayOutputStream();

    HttpURLConnection conn = null;

    byte[] fileBuffer = null;

    Integer width = null;

    Integer height = null;


    try {

    File fnew=new File(path);


    String extension = getFileExtension(fnew);


    BufferedImage originalImage = ImageIO.read(fnew);


    width = originalImage.getWidth();

    height = originalImage.getHeight();


    if( "png".equals(extension) ) {


    BufferedImage resultImage = imageToBufferedImageTransparency(originalImage, originalImage.getWidth(), originalImage.getHeight());


    ImageIO.write(resultImage, extension, baos);


    } else {

    ImageIO.write(originalImage, extension, baos);

    }

     }catch (IOException e) {

    throw new IOException("Can't read input file! - " + path);

} finally {

if( conn != null )

conn.disconnect();

}

}


private static BufferedImage imageToBufferedImageTransparency(Image image, int width, int height) {

BufferedImage dest = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);

Graphics2D g2 = dest.createGraphics();


g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

                g2.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);

                g2.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);

                g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);


g2.drawImage(image, 0, 0, null);

g2.dispose();

return dest;

}


'JAVA' 카테고리의 다른 글

[JAVA] LIST형 Remove 하기  (1) 2019.04.16
[JAVA] URLConnection HTTPS 처리  (1) 2019.03.14
[JAVA] 자동리소스 닫기  (2) 2018.08.02
JSON 사용하기  (0) 2013.06.21

기본적으로 gradle 설치가 되어 있어야 한다.


바꾸는 명령어는 간단하다.


pom.xml이 있는 경로로 가서 


gradle init --type pom


이렇게 명령어를 실행하면 된다.


테스트 결과 완벽하게 모든 dependencies 옮겨지지 않는다.


일부 손이 가야 하지만 그래도 Maven보다 빠르고 쓰기 편하니 그걸로 족하다.

List 를 삭제 할 경우 아래와 같이 작성을 할 경우 오류가 발생합니다.

for(int i = 0; i < list.size(); i++ ) {
    list.remove(i);
}


List 를 삭제 하고자 할 경우에는 아래와 같이 iterator을 활용하여 삭제 하도록 합니다.

list.add(“A”);
list.add(“B”);
list.add(“C”);
for(Iterator<String> it = list.iterator() ; it.hasNext() ; ) {
    it.next();
    it.remove();
}


'JAVA' 카테고리의 다른 글

PNG 이미지 배경 투명하게 처리  (0) 2020.02.03
[JAVA] URLConnection HTTPS 처리  (1) 2019.03.14
[JAVA] 자동리소스 닫기  (2) 2018.08.02
JSON 사용하기  (0) 2013.06.21

나 같은 경우 서브업무로 업무가 분리되어 있는 경우 업무를 처리하고 특정 Interface를 구현한 Class를 찾아서 후처리하는 기능 때문에 필요한 기능이었습니다.

추가적으로 찾은 Class에서 특정 Annotaion을 사용한 Method를 찾아서 실행하도록 하였습니다.


ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(false); 
provider.addIncludeFilter(new AssignableTypeFilter(Interface명.class));

Set components = provider.findCandidateComponents("Package명");  // co/kr/test형식

for (BeanDefinition component : components) {
    Class<?> clazz = Class.forName(component.getBeanClassName());
    logger.debug("Class Name : " + clazz.getName() );

    Method[] methods = clazz.getMethods();
    for (Method method : methods) {
        if( method.isAnnotationPresent(PostApprove.class) ) {
            logger.debug("Method Name : " + method.getName() );
            PostApprove annotation = method.getAnnotation(Annotation명.class);
            logger.debug("Annotation CODE : " + code + ", KEY : " + key );

            if( Arrays.asList(annotation.code()).contains(code) ) {
                String serviceValue = method.getDeclaringClass().getAnnotationsByType(Service.class)[0].value();
                ApproveHelper helper = (ApproveHelper) context.getBean(serviceValue);
         helper.postApprove(code, key);
           }
        }

    }
}


JAVA에서 SSL 적용된 사이트에 접근하기 위해 HttpsURLConnection을 사용하게 됩니다.

하지만 결과 적으로 HttpsURLConnection만 사용한다 하여 접근이 되지 않는 현상이 발생합니다.


String htmlUrl = "https://test.domain.co.kr";

HttpURLConnection conn  = (HttpURLConnection) new URL(htmlUrl).openConnection();

conn.setRequestMethod("GET");

conn.setRequestProperty("User-Agent", "Mozilla/5.0");


StringBuffer sb = new StringBuffer();

BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8"));

String inputLine;


while ((inputLine = in.readLine()) != null) {

sb.append(inputLine);

}


in.close();


단순이 이렇게 HttpURLConnection를 사용할 경우 아래와 같은 오류를 발생 시킨다.

Exception in thread "main" javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

위의 오류는 해당 사이트에 SSL 인증서가 신뢰하는 기관 인증서가 없거나 SSL/TLS암호화 버전이 맞지 않는 경우 발생한다고 한다.

인터넷을 찾아 보면 Client에도 KeyStore를 만들어 주어 해결하는 방법이 있다고는 하나 모든 Client 에 설치하는건 좀 무리가 있다고 본다.


하지만 프로그램을 하다 보면 반드시 접근해야 하는 경우가 생긴다.

그래서 유효하지 않은 SSL 인증서를 사용하는 서버에 접근하도록 HttpURLConnection 를 설정을 해야 한다.

BufferedReader br = null;

StringBuilder sb = new StringBuilder();

String line = null;


try {

String htmlUrl = "https://test.domain.co.kr";

TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {

public X509Certificate[] getAcceptedIssuers() {

return null;

}

public void checkClientTrusted(X509Certificate[] certs, String authType) {

}

public void checkServerTrusted(X509Certificate[] certs, String authType) {

}

} };


SSLContext sc = SSLContext.getInstance("SSL");

sc.init(null, trustAllCerts, new SecureRandom());

HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());


HttpsURLConnection conn = (HttpsURLConnection) new URL(htmlUrl).openConnection();


InputStream is = conn.getInputStream();

br = new BufferedReader(new InputStreamReader(is, "UTF-8"));

while ((line = br.readLine()) != null) {

sb.append(line);

}


} catch (NoSuchAlgorithmException | IOException | KeyManagementException e) {

e.printStackTrace();

}

System.out.println(sb.toString());



'JAVA' 카테고리의 다른 글

PNG 이미지 배경 투명하게 처리  (0) 2020.02.03
[JAVA] LIST형 Remove 하기  (1) 2019.04.16
[JAVA] 자동리소스 닫기  (2) 2018.08.02
JSON 사용하기  (0) 2013.06.21

JAVA 7 버전이후 부터 추가된 항목으로

java.lang.AutoCloseable 사용한 객체들은 close() 없이 자동을 안전하게 리소스를 닫아 준다.


예를 들어 poi의 XSSFWorkbook 의 경우

JAVA 6에서는 


XSSFWorkbook workbook = null;

try {

workbook = XSSFWorkbook(upFileStream);

...

} finally {

workbook.close();

}


이렇게 객체를 해제해 줘야 했으나 JAVA 7부터는


XSSFWorkbook workbook = null;

try {

workbook = XSSFWorkbook(upFileStream);

...

} finally {

}


Close 없이 자동 해제됩니다.


XSSFWorkbook API를 보면


org.apache.poi.xssf.usermodel

Class XSSFWorkbook

  • All Implemented Interfaces:
    java.io.Closeable, java.lang.AutoCloseable, java.lang.Iterable<Sheet>, Workbook

저 부분이 보일겁니다~


'JAVA' 카테고리의 다른 글

PNG 이미지 배경 투명하게 처리  (0) 2020.02.03
[JAVA] LIST형 Remove 하기  (1) 2019.04.16
[JAVA] URLConnection HTTPS 처리  (1) 2019.03.14
JSON 사용하기  (0) 2013.06.21

Java Configuration을 사용할 경우

public class WebMvcConfig extends WebMvcConfigurerAdapter {

@Override

public void addResourceHandlers(ResourceHandlerRegistry registry) {

registry

.addResourceHandler("/resources/**")

.addResourceLocations(

"/resources/",

"classpath:/META-INF/resources/resources"

);

}

}


xml 설정을 사용할 경우


<resources mapping="/resources/**" location="classpath:/META-INF/resources/resources/" />

- ajax로 보낼 경우

@RequestParam(value="arr[]" String[] arr)


- get 또는 post로 보낼 경우

@RequestParam(value="arr" String[] arr)

Data를 저장 시 저장되는 모든 정보를 이력으로 남겨 놓기 위하여 작성했습니다.


말들이 하도 많아서...ㅜㅜ



import java.lang.reflect.Method;

import java.util.Enumeration;


import javax.annotation.Resource;

import javax.servlet.http.HttpServletRequest;


import org.apache.commons.lang3.ArrayUtils;

import org.apache.commons.lang3.StringUtils;

import org.aspectj.lang.ProceedingJoinPoint;

import org.aspectj.lang.annotation.Around;

import org.aspectj.lang.annotation.Aspect;

import org.aspectj.lang.reflect.MethodSignature;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.security.core.context.SecurityContextHolder;

import org.springframework.security.core.userdetails.UserDetails;

import org.springframework.stereotype.Component;

import org.springframework.util.ObjectUtils;

import org.springframework.web.context.request.RequestContextHolder;

import org.springframework.web.context.request.ServletRequestAttributes;


import com.duegosystem.esh.common.utils.RequestUtils;

import com.duegosystem.esh.config.aspect.operate.annotation.OperateLog;

import com.duegosystem.esh.config.aspect.operate.service.UserOpertHistService;

import com.duegosystem.esh.config.aspect.operate.vo.OperateHistVo;

import com.duegosystem.esh.config.security.vo.UserVo;


/**

 * @author Duego-Choi

 *

 */

@Aspect

@Component

public class OperateAdviceLogging {


private static final Logger logger = LoggerFactory.getLogger(OperateAdviceLogging.class);


@Resource(name = "userOpertHistService")

private UserOpertHistService userOpertHistService;


/**

* 등록 수정 삭제 시에만 적용합니다.

*

* @param joinPoint

* @return

* @throws Throwable

*/

@Around("execution(* com.duegosystem..*Controller.insert*(..)) || "

+ "execution(* com.duegosystem..*Controller.update*(..)) || "

+ "execution(* com.duegosystem..*Controller.delete*(..))")

public Object aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {


logger.debug("Operate History Logging save processing.......................................");


Object principal = (Object) SecurityContextHolder.getContext().getAuthentication().getPrincipal();


HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes())

.getRequest();


String httpMethod = request.getMethod();

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

Method method = signature.getMethod();


logger.debug("httpMethod : " + httpMethod);

logger.debug("Class Method : " + method);


OperateHistVo operateHistVo = null;


/*

* 저장 수정 삭제 일경우만 사용하도록 하기 위해 POST 형식일 때만 적용되어지도록 처리

*/

if ("POST".equals(httpMethod)) {


if ((principal instanceof UserDetails)) {


operateHistVo = new OperateHistVo();


// 사용자 정보

UserVo user = (UserVo) principal;

logger.debug("empno : " + user.getEmpno());

logger.debug("emplNm : " + user.getEmplNm());


operateHistVo.setOpertId(user.getEmpno());

operateHistVo.setOpertNm(user.getEmplNm());


// 작업자 아이피

String ipAddress = RequestUtils.getRemoteIP(request);

logger.debug("ipAddress : " + ipAddress);

operateHistVo.setOpertIp(ipAddress);


// 접근 경로(메뉴 패턴)

String requestUri = request.getRequestURI();

String contextPath = request.getContextPath();

String pattern = requestUri.replaceAll("(^" + contextPath + ")|((\\.[^\\.]*)$)|((/[^/]+){1}/*$)", "")

+ "/";

logger.debug("Url pattern : " + pattern);

operateHistVo.setPattern(pattern);


String operateFile = requestUri.replace(contextPath, "").replace(pattern, "");

String operateType = "insert";

if (operateFile.startsWith("update")) {

operateType = "update";

} else if (operateFile.startsWith("delete")) {

operateType = "delete";

}

logger.debug("Operate Type : " + operateType);

operateHistVo.setOpertTy(operateType);


/*

* OperateLog Annotation을 통해서 등록하고자 하는 파라메터 또는 등록지 말아야 할 파라메터를

* 지정하였을 경우 처리합니다.

*

* 우선 순위는 등록해야할 파라메터가 있는 경우가 우선입니다.

*/

Enumeration<String> params = request.getParameterNames();


if (method.isAnnotationPresent(OperateLog.class)) {

OperateLog operateLog = method.getDeclaredAnnotation(OperateLog.class);


String[] saveParams = operateLog.params();

String[] notSaveParams = operateLog.notSaveParam();


// 저장하고자 하는 파라메타명을 설정하였을 경우

if (!ObjectUtils.isEmpty(saveParams)) {

while (params.hasMoreElements()) {

String paramName = (String) params.nextElement();

if (ArrayUtils.contains(saveParams, paramName)) {

if (!StringUtils.isEmpty(request.getParameter(paramName))) {

operateHistVo.addParam(paramName, request.getParameter(paramName));

}

}

}


// 저장하지 않을 파라메타명을 성정하였을 경우

} else if (!ObjectUtils.isEmpty(notSaveParams)) {

while (params.hasMoreElements()) {

String paramName = (String) params.nextElement();

if (ArrayUtils.contains(notSaveParams, paramName)) {

continue;

} else {

if (!StringUtils.isEmpty(request.getParameter(paramName))) {

operateHistVo.addParam(paramName, request.getParameter(paramName));

}

}

}

} else {

while (params.hasMoreElements()) {

String paramName = (String) params.nextElement();

if (!StringUtils.isEmpty(request.getParameter(paramName))) {

operateHistVo.addParam(paramName, request.getParameter(paramName));

}

}

}


} else {

while (params.hasMoreElements()) {

String paramName = (String) params.nextElement();

if (!StringUtils.isEmpty(request.getParameter(paramName))) {

operateHistVo.addParam(paramName, request.getParameter(paramName));

}

}

}


userOpertHistService.insert(operateHistVo);

}

}


Object obj = joinPoint.proceed();


/*

* Method에 해당하는 처리가 모두 끝난 후 후처리로 성공 상태 값을 Y로 바꿔준다.

*/

if ("POST".equals(httpMethod)) {

if (!ObjectUtils.isEmpty(operateHistVo)) {

try {

userOpertHistService.updateSuccess(operateHistVo.getOpertHistSeq());

} catch (Exception e) {

logger.error("OperateHist Advice Processing Error......!!!", e);

}

}

}


return obj;

}

}


Gradle의 멀티 프로젝트를 이용하여 모듈식 웹 프로젝트를 만들고 싶었다.

 

공통 부분과 그렇지 않은 부분을 업무별로 구성하여 각 프로젝트마다 필요한 업무를 조합하여 제공하고자 하는것이 목표였다.

 

열심히 구글링을 하였으나 멀티 프로젝트를 만드는 것은 많이 있지마 웹을 처리하는 방식은 없었다.

 

그래서 그냥 한번 이것 저것 찾아 보면서 한번 만들어 보기로 했다.

 

1. 전체 프로젝트 구조

 

 

프로젝트의 순서는 다음과 같이 정의 했다.

 

kamsi-system을 기본으로 하여 하위 프로젝트는 다음 순과 같이 정의를 하였다.


kamsi-common > kamsi-planner

 

kamsi-common을 kamsi-planner에서 Import 하여 배포하는 프로젝트라고 정의 했다.

 

 

 

2. Root Project

 

2.1. settings.gradle 생성

 

rootProject.name = 'kamsi-system'


include 'kamsi-common'
include 'kamsi-planner'

 

 

 

2.2. build.gradle

 

allprojects {


apply plugin: 'java'
apply plugin: 'eclipse-wtp'

ext {
     springVersion = '4.3.6.RELEASE'
     springSecurityVersion = '4.2.0.RELEASE'
     tilesVersion = '3.0.7'
     mybatisVersion = '3.4.1'
     mybatisSpringVersion = '1.3.0'
     log4jVersion = '2.8'
     poiVersion = '3.15'
}

 

repositories {
     mavenCentral()
     maven {
          name "OJDBC"
          url "http://repo.spring.io/libs-release"
     }
     maven {
          name "eGovFramework"
          url "http://maven.egovframe.kr:8080/maven/"
     }
 }

 

 dependencies {

  compile "org.springframework:spring-aop:${springVersion}"
  compile "org.springframework:spring-context:${springVersion}"
  compile "org.springframework:spring-web:${springVersion}"
  compile "org.springframework:spring-webmvc:${springVersion}"
  compile "org.springframework:spring-jdbc:${springVersion}"

  compile "org.springframework.security:spring-security-acl:${springSecurityVersion}"
  compile "org.springframework.security:spring-security-aspects:${springSecurityVersion}"
  compile "org.springframework.security:spring-security-config:${springSecurityVersion}"
  compile "org.springframework.security:spring-security-core:${springSecurityVersion}"
  compile "org.springframework.security:spring-security-taglibs:${springSecurityVersion}"
  compile "org.springframework.security:spring-security-web:${springSecurityVersion}"

  compile "org.springframework:spring-websocket:${springVersion}"

  compile "egovframework.rte:egovframework.rte.ptl.mvc:3.5.0"

  compile "org.mybatis:mybatis:${mybatisVersion}"
  compile "org.mybatis:mybatis-spring:${mybatisSpringVersion}"

  compile "org.aspectj:aspectjweaver:1.9.1"

  compile "javax.servlet:javax.servlet-api:3.1.0"
  compile "javax.servlet:jstl:1.2"
  compile "javax.servlet.jsp:jsp-api:2.2"

  compile "javax.validation:validation-api:1.1.0.Final"
  compile "com.fasterxml.jackson.jaxrs:jackson-jaxrs-base:2.5.2"

  compile "org.apache.tiles:tiles-api:${tilesVersion}"
  compile "org.apache.tiles:tiles-jsp:${tilesVersion}"

  compile "commons-io:commons-io:2.5"
  compile "commons-fileupload:commons-fileupload:1.3.2"
  compile "commons-beanutils:commons-beanutils:1.9.2"
  compile "org.apache.commons:commons-dbcp2:2.1"
  compile "org.apache.commons:commons-lang3:3.5"

  compile "org.apache.logging.log4j:log4j-slf4j-impl:${log4jVersion}"
  compile "org.apache.logging.log4j:log4j-core:${log4jVersion}"
  compile "org.apache.logging.log4j:log4j-api:${log4jVersion}"

  compile "org.hibernate:hibernate-validator:5.1.3.Final"

  compile "org.apache.poi:poi-ooxml-schemas:${poiVersion}"
  compile "org.apache.poi:poi:${poiVersion}"
  compile "org.apache.poi:poi-ooxml:${poiVersion}"
  compile "org.apache.poi:poi-scratchpad:${poiVersion}"

  compile "com.oracle:ojdbc6:12.1.0.1-atlassian-hosted"
  compile "org.bgee.log4jdbc-log4j2:log4jdbc-log4j2-jdbc4.1:1.16"

  compileOnly "org.projectlombok:lombok:1.16.20"
  compileOnly 'javax.servlet:javax.servlet-api:3.1.0'

}

}


subprojects {

task initSourceFolders {
     sourceSets*.java.srcDirs*.each {
         if( !it.exists() ) {
             it.mkdirs()
         }
     }

     sourceSets*.resources.srcDirs*.each {
         if( !it.exists() ) {
             it.mkdirs()
         }
     }


// webapp 폴더 생성

   def webappDir = new File("${projectDir}/src/main/webapp/WEB-INF")

   if( !webappDir.exists() ) {

webappDir.mkdirs()

   }

 }

}

 

위의 두가지 settings.gralde와 build.gradle을 생성 또는 수정한 후 Gradle build를 실행한다.

 

실행하고 나면 Eclipse 에 총 3개의 프로젝트가 생성되는것을 확인할 수 있다.

 

allprojects { ... } 생성되는 모든 프로젝트에 적용 되어져 모든 프로젝트에 Dependence에 정의된 라이브러리 들이 추가 된다.


subprojects { ... } 에 있는 내용은 하위 프로젝트에 source 파일이 담길 [ src/main/java, src/test/java] 와 [ src/main/webapp/WEB-INF ]를 생성하도록 설정 한다.

 

 

3. kamsi-common 프로젝트

 

앞서 말한바와 같이 프로젝트의 공통 부분이 들어갈 최상위 프로젝트이다.

 

Java Config 및 Security 또한 기본으로 사용되는 WEB Resource 등을 관리한다고 가정한다.

 

 

 

3.1 build.gradle

 

//apply plugin: 'war'

group = 'com.kamsi'
version = '0.0.1-SNAPSHOT'

 

jar {

metaInf {
    from 'src/main/webapp'
    into 'resources'

}

destinationDir rootProject.buildDir

}

 

위의 붉고 굵은 글씨의 항목이 중요한 부분이다.

 

지금까지 상위항목을 사용하기 위하여 이것저것을 해 보았지만 적용이 되지 않았다.

 

이클립스에서 java build path에 해당 프로젝트를 add 해도 적용이 되어지지 않았다.

 

그래서 구글링한 결과 사용하려면 jar 파일로 저장을 해서 import 시키는 것이 좋을 듯하다는 판단으로 소스를 jar로 묶어서 import 하였으나... 문제는 jsp 등 WEB-INF 하위에 있는 항목들을 불러 오지 못하는.... 그런 경우가 생겨 버렸다.

 

결국 jsp를 사용하고자 하면 jar 파일안에 있는 META-INF/resources 폴더 밑으로 들어가야 한다고 한다.

java 쪽에서 그렇게 정리를 해 놨다고 한다.

 

위의 붉고 굵은 글씨로 된 코드가 바로 그 부분이다.


이후 우리가 작성하던 방식대로 프로그램을 작성하면 된다.


4. kamsi-planner 프로젝트


해당 프로젝트에서는 kamsi-common을 사용하여 공통을 제외한 planner에 대하여만 작성을 하도록 설정한다.


4.1 build.gradle


apply plugin: 'war'


group = 'com.kamsi'

version = '0.0.1-SNAPSHOT'


war {

    baseName = 'duego-esh-web'

    version = '0.0.2-SNAPSHOT'

}


dependencies {

compile files("../build/kamsi-common-0.0.1-SNAPSHOT.jar")

}


jar {

    metaInf {

    from 'src/main/webapp'

    into 'resources'

    }


destinationDir rootProject.buildDir

}


/*********************************************************************

 * 테스트를 위한 jar 생성

 */

[compileJava, compileTestJava]*.options*.encoding = 'UTF-8' // 인코딩 UTF-8로 통일.


task subprojectBuild(type: Test) {

dependsOn ':kamsi-common:jar'

}


assemble.finalizedBy(subprojectBuild)

위의 소스와 같이 build과 정중 assemble task를 실행할 때 kamsi-common 프로젝트를 jar로 묶어주는 도록 처리를 했으며

또한 jar 파일을 묶은 kamsi-common 프로젝트를 dependencies 하도록 설정하였다.




이렇게 다 작성을 하고 kamsi-planner에서 WEB을 구동하였더니.....

Web Resources(css, javascript)를 찾아 오지 못하는 현상이 발생했다.


이러한 경우 jar 파일의 Web Resource 를 읽어 올수 있도록 처리를 해 줬다.


https://bit.ly/2lRwttG <-- 여기서 확인


이상으로 아주 간략하게 설정을 해 본 것이고... 

아주 초보적인 관점에서 처리 한것이라서... 


더 공부를 진행해야 겠다는 생각만이...ㅜㅜ


apache.commons.compress  받는곳 

https://commons.apache.org/proper/commons-compress/download_compress.cgi

 

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;


public class ZipTest {

 public static void main(String[] args) throws Throwable {
  String path = "C:\\Users\\yuri\\Downloads\\commons-compress-1.16.1-bin\\commons-compress-1.16.1";
  //compress(path);
  decompress(path + "\\테스트.zip", path + "\\test");
 }

 /**
  * <pre>파일 압축하기</pre>
  * 파라메타 path가 폴더 이면 폴더 전체를 압축하고 파일경우는 파일만 압축
  * @param path
  * @throws IOException
  */
 public static void compress(String path) throws IOException {

  File file = new File(path);

  String files[] = null;

  // 파일이 디렉토리 일경우 리스트를 읽어오고
  // 파일이 디렉토리가 아니면 첫번째 배열에 파일이름을 넣는다.
  if (file.isDirectory()) {
   files = file.list();
  } else {
   files = new String[1];
   files[0] = file.getName();
   System.out.println(file.getName().getBytes());
  }

  // buffer size  int size = 1024;
  byte[] buf = new byte[size];

  String outZipNm = path + "\\테스트.zip";
  FileInputStream fis = null;
  ZipArchiveOutputStream zos = null;
  BufferedInputStream bis = null;

  try {

   // Zip 파일생성
   zos = new ZipArchiveOutputStream(new BufferedOutputStream(new FileOutputStream(outZipNm)));

   for (int i = 0; i < files.length; i++) {

    // 해당 폴더안에 다른 폴더가 있다면 지나간다.
    if (new File(path + "/" + files[i]).isDirectory()) {
     continue;
    }

    // encoding 설정
    zos.setEncoding("UTF-8");

    // buffer에 해당파일의 stream을 입력한다.
    fis = new FileInputStream(path + "/" + files[i]);

    bis = new BufferedInputStream(fis, size);

    // zip에 넣을 다음 entry 를 가져온다.
    zos.putArchiveEntry(new ZipArchiveEntry(files[i]));

    // 준비된 버퍼에서 집출력스트림으로 write 한다.
    int len;

    while ((len = bis.read(buf, 0, size)) != -1) {
     zos.write(buf, 0, len);
    }

    bis.close();

    fis.close();

    zos.closeArchiveEntry();

   }

   zos.close();

  } catch (FileNotFoundException e) {
   e.printStackTrace();
  } finally {

   if (zos != null) {
    zos.close();
   }

   if (fis != null) {
    fis.close();
   }

   if (bis != null) {
    bis.close();
   }

  }
 }

 /**
  * <pre>파일압축 해제</pre>
  *
  * @param zipFileName 압축파일명
  * @param directory 압축이 풀릴 파일 경로
  * @throws Throwable
  */
 public static void decompress(String zipFileName, String directory) throws Throwable {

        File zipFile = new File(zipFileName);
        FileInputStream fis = null;
        ZipInputStream zis = null;
        ZipEntry zipentry = null;

        try {

            //파일 스트림
            fis = new FileInputStream(zipFile);

            //Zip 파일 스트림
            zis = new ZipInputStream(fis);

            //entry가 없을때까지 뽑기
            while ((zipentry = zis.getNextEntry()) != null) {

                String filename = zipentry.getName();

                File file = new File(directory, filename);

                //entiry가 폴더면 폴더 생성
                if (zipentry.isDirectory()) {
                    file.mkdirs();
                } else {
                    //파일이면 파일 만들기
                    createFile(file, zis);
                }

            }

        } catch (Throwable e) {
            throw e;
        } finally {

            if (zis != null)
                zis.close();

            if (fis != null)
                fis.close();

        }

    }

 /**
  * <pre>파일 경로에 압축 푼 파일 생성</pre>
  *
  * @param file
  * @param zis
  * @throws Throwable
  */
 private static void createFile(File file, ZipInputStream zis) throws Throwable {

        //디렉토리 확인
        File parentDir = new File(file.getParent());

        //디렉토리가 없으면 생성하자
        if (!parentDir.exists()) {
            parentDir.mkdirs();
        }

        //파일 스트림 선언
        try (FileOutputStream fos = new FileOutputStream(file)) {

            byte[] buffer = new byte[256];
            int size = 0;
            //Zip스트림으로부터 byte뽑아내기
            while ((size = zis.read(buffer)) > 0) {
                //byte로 파일 만들기
                fos.write(buffer, 0, size);
            }

        } catch (Throwable e) {
            throw e;
        }

    }

}

 

참조 :

압축하기 : 출처: http://javacpro.tistory.com/21 [버물리의 IT공부]

압축 풀기 : http://nowonbun.tistory.com/321 [명월 일지]

'JAVA > Common' 카테고리의 다른 글

ArrayList 정렬 및 자르기  (0) 2016.03.07
형 변환 모음...  (0) 2015.05.28
인코딩 한방에 테스트 하기  (0) 2015.04.23
String.format()을 이용하여 Date 표현하기  (0) 2013.10.01

Spring Security 설정 파일에서 다음과 같이 설정한다.


@Configuration

@Import({SecurityBeanConfig.class})

@EnableWebSecurity

public class SecurityConfig extends WebSecurityConfigurerAdapter {


  ...


@Autowired

private FilterSecurityInterceptor filterSecurityInterceptor;


  ...


@Override

public void configure(WebSecurity web) throws Exception {

web

.ignoring()

.antMatchers("/resources/**")

.and()

.privilegeEvaluator(webInvocationPrivilegeEvaluator());

}  


   ...


/**

* Cusome Tag를 사용하여 Web 페이지에서 권한을 체크하고 싶을 때 사용함.

*

* <code>

* <sec:authorize url="/admin/stats/index.jsp">

* <a href="<spring:url value="/admin/stats/index.jsp"/>">link</a>

* </sec:authorize>

* </code>

*

* @return

*/

@Bean

public WebInvocationPrivilegeEvaluator webInvocationPrivilegeEvaluator(){

return new DefaultWebInvocationPrivilegeEvaluator(filterSecurityInterceptor);

}

}


사용은 위의  주석과 같이


체크하고자 하는 경로를 넣어 주면 접근이 가능한지 여부를 판단하여 준다.


<sec:authorize url="/admin/stats/index.jsp">

<a href="<spring:url value="/admin/stats/index.jsp"/>">link</a>

</sec:authorize>


1. Eclipse 플러그인 설정


- Eclipse Marketplace 에서 gradle 검색


- Buildship Gradle Integration 2.0 인스톨




- 설치 완료 후 Ecilpse 재시작




2. Gradle 프로젝트 생성


- File > New > Project 메뉴 선택


- Gradle > Gradle Project 선택





3. Source Folder 및 Web Folder 생성


- Java Resources 에 Source Folder 추가

  

  : src/main/resources





- 하단 src/main 하위폴더로 Web Folder 생성


  : webapp

  : webapp/WEB-INF




전체 폴더 구조






3. Gradle 설정


- build.gradle 파일 오픈


- plugin 설정


apply plugin: 'java'

apply plugin: 'eclipse-wtp'

apply plugin: 'war'



- property 설정


ext {

  springVersion = '4.3.6.RELEASE'

  springSecurityVersion = '4.2.0.RELEASE'

  tilesVersion = '3.0.7'

  mybatisVersion = '3.4.1'

  mybatisSpringVersion = '1.3.0'

  log4jVersion = '2.8'

  poiVersion = '3.15'

}


- repositories 설정

repositories {
  mavenCentral()
  maven {
    name "eGovFramework"
    url "http://www.egovframe.go.kr/maven/"
  }
  maven {
    name "OJDBC"
    url "https://mvnrepository.com/artifact/com.jslsolucoes/ojdbc6/"
  }
}

dependencies 설정


dependencies {

  compile "org.springframework:spring-aop:$rootProject.ext.springVersion"

  compile "org.springframework:spring-context:$rootProject.ext.springVersion"
  ...

}

+ Recent posts