public static String maskName(String name) {
    String rname = null;

    // 이름이 외자인 사람
    if(name.length()<=2) {
        rname = name.replaceFirst("(.)(.)", "$1*");

    // 이름이 3자인 사람
    } else if(name.length()==3) {
        rname = name.replaceFirst("(.)(.+)(.)", "$1*$3");

    // 이름이 4자 이상인 사람
    } else {
        rname = 
            name.substring(0,1) + 
            name.substring(1, name.length()-1).replaceAll(".", "*") + 
            name.substring(name.length()-1);
    }

    return rname;
}

 

이름 마스킹.

2자,3자,4자 이상 각각 처리.

'개발이야기 > java' 카테고리의 다른 글

Java Reflection - private 변수값 수정하기  (0) 2022.01.20
Java Reflection - private 변수값 읽어오기  (0) 2022.01.20
Instagram4j 구현  (0) 2022.01.17
파파고 번역 구현  (0) 2022.01.17
Instagram4j - Maven Dependency  (0) 2022.01.14
package common.util.api.sns;

import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.CompletableFuture;

import com.github.instagram4j.instagram4j.IGClient;
import com.github.instagram4j.instagram4j.IGClient.Builder;
import com.github.instagram4j.instagram4j.actions.users.UserAction;
import com.github.instagram4j.instagram4j.models.media.ImageVersions;
import com.github.instagram4j.instagram4j.models.media.ImageVersionsMeta;
import com.github.instagram4j.instagram4j.models.media.timeline.Comment.Caption;
import com.github.instagram4j.instagram4j.models.media.timeline.ImageCarouselItem;
import com.github.instagram4j.instagram4j.models.user.User;
import com.github.instagram4j.instagram4j.models.media.timeline.TimelineMedia;
import com.github.instagram4j.instagram4j.models.media.timeline.VideoCarouselItem;
import com.github.instagram4j.instagram4j.requests.feed.FeedUserRequest;
import com.github.instagram4j.instagram4j.responses.feed.FeedUserResponse;

import common.util.CryptoUtil;
import common.util.ReflectUtil;
import common.util.StringUtil;
import common.util.stream.FileUtil;
import common.util.stream.StreamUtil;
import mvc.Config;
import mvc.model.DataMap;
import mvc.model.DataSet;

/**
 * 인스타그램 Feed 가져오기
 * 
 * @apiNote 인스타그램 Feed 가져오기
 * @since 2020-01-01
 * @author 청록비
 * @version 2020-01-31
 */

public class InstagramManager {
	private static Builder builder;
	private static IGClient client;
	private static String uploadPath;
	private static String uploadUrl;
	
	static {
		uploadUrl = Config.get("path.upload")+"/social/insta";
		uploadPath = Config.get("path.root") + uploadUrl;
	}
	
	
	private static void getInstance() {
		String username = Config.get("account.instagram.username");
		String password = Config.get("account.instagram.password");
		try {
			if (builder == null) {
				builder = IGClient.builder();
			}

			if(client==null) {
				client = builder.username(username).password(password).login();
			}

		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	public static DataMap getUserTimeline(String targetName) throws Exception {
		return getUserTimeline(targetName, null);
	}
	
	public static DataMap getUserTimeline(String targetName, String maxId) throws Exception {

		// 초 : 1000밀리 / 60초 / 30분 : 30분이 지날 때마다 피드 html을 web에서 가져온다.
		long time = System.currentTimeMillis() / 1000 / 60 / 30;

		String feedSerFilePath = null;
		
		if(StringUtil.isEmpty(maxId)) {
			feedSerFilePath = uploadPath + "/" +targetName+ "/feed_first_" +time+ ".ser";
		} else {
			feedSerFilePath = uploadPath + "/" +targetName+ "/feed_" +maxId+ "_" +time+ ".ser";
		}
		
		File feedSerFile = new File(feedSerFilePath);

		if (feedSerFile.exists() && feedSerFile.length() > 100) {
			DataMap serialFeedSet = getSerialObject(feedSerFile);
			return serialFeedSet;
		}
		
		getInstance();
		
		DataMap feedResult = new DataMap();
		DataSet feedSet = new DataSet();
		feedResult.put("data", feedSet);
		
		try {

			// String auth = client.getAuthorization();
			// String token = client.getCsrfToken();

			CompletableFuture<FeedUserResponse> feedActs = null;
			
			InstaUserInfo info = getUserInfo(targetName);
			long userPk = info.getUserPk();
			
			FeedUserRequest request = null;
			if(StringUtil.isEmpty(maxId)) {
				request = new FeedUserRequest(userPk);
			} else {
				request = new FeedUserRequest(userPk, maxId);
			}
			
			feedActs = client.sendRequest(request);
			FeedUserResponse feedResponse = feedActs.get();
			
			maxId = feedResponse.getNext_max_id();
			feedResult.put("maxId", maxId);
			
			Iterator<TimelineMedia> feedIt = feedResponse.getItems().iterator();
			FeedUploadWorker uploadWorker = new FeedUploadWorker(targetName);
			
			while (feedIt.hasNext()) {
				TimelineMedia feed = feedIt.next();
				String id = feed.getId();
				String code = feed.getCode();
				Caption caption = feed.getCaption();
				String text = "";
				if(caption!=null) {
					text = caption.getText();
				}

				File picDir = new File(uploadPath + "/" + feed.getUser().getUsername());
				String[] picFiles = picDir.list(new FilenameFilter() {
					@Override
					public boolean accept(File dir, String name) {
						return name.startsWith(id);
					}
				});
				

				String picture = null;
				String pictureUrl = null;

				if(picFiles!=null && picFiles.length>0) {
					picture = uploadUrl + "/" + feed.getUser().getUsername() + "/" + picFiles[0];
				} else {
					try {
						Object mediaValue = null;
						int mediaType = Integer.parseInt(feed.getMedia_type());
						switch (mediaType) {
							case 1:
							case 2:
							case 8: {
								mediaValue = ReflectUtil.getDeclaredFieldValue(feed, "carousel_media");
								
								if(mediaValue==null) {
									mediaValue = ReflectUtil.getDeclaredFieldValue(feed, "image_versions2");
								}
								
								break;
							}
							
							default: {
								break;
							}
						}
	
						if (mediaValue != null && mediaValue instanceof List) {
							List<?> mediaList = (List<?>) mediaValue;
							if (mediaList.size() > 0) {
								Object objMedia = mediaList.get(0);
	
								ImageVersionsMeta media = null;
								if (objMedia instanceof ImageVersionsMeta) {
									media = (ImageVersionsMeta) objMedia;

								} else if (objMedia instanceof VideoCarouselItem) {
									VideoCarouselItem item = (VideoCarouselItem) objMedia;
									mediaList = (List<?>) item.getImage_versions2().getCandidates();
									if(mediaList.size()>1) {
										media = (ImageVersionsMeta) mediaList.get(1);
									} else {
										media = (ImageVersionsMeta) mediaList.get(0);	
									}
									
								} else if (objMedia instanceof ImageCarouselItem) {
									ImageCarouselItem item = (ImageCarouselItem) objMedia;
									mediaList = (List<?>) item.getImage_versions2().getCandidates();
									if(mediaList.size()>1) {
										media = (ImageVersionsMeta) mediaList.get(1);
									} else {
										media = (ImageVersionsMeta) mediaList.get(0);	
									}
								}
	
								pictureUrl = ReflectUtil.getDeclaredFieldValue(media, "url").toString();
							}
						} else if(mediaValue instanceof ImageVersions) {
							ImageVersions mediaImages = (ImageVersions)mediaValue;
							List<ImageVersionsMeta> mediaList = mediaImages.getCandidates();
							if(mediaImages.getCandidates().size()>1) {
								pictureUrl = mediaList.get(1).getUrl();	
							} else {
								pictureUrl = mediaList.get(0).getUrl();
							}
						}
						
						String pictureFileName = pictureUrl.split("\\?")[0];
						String pictureFileExt = pictureFileName.substring(pictureFileName.lastIndexOf("."));

						picture = uploadUrl + "/" + feed.getUser().getUsername() + "/" + id + pictureFileExt;
						
						if(Boolean.TRUE) {
							File file = new File(Config.get("path.root") + picture);
							
							if (!file.exists()) {
								uploadWorker.add(pictureUrl, file);
							}
						}
					} catch (Exception e) {
						e.printStackTrace();
						continue;
					}
				}
				
				feedSet.addRow();
				feedSet.put("id", id);
				feedSet.put("code", code);
				feedSet.put("text", text);
				feedSet.put("picture", picture);
			}

			if(uploadWorker.size()>0) {
				Thread uploadThread = new Thread(uploadWorker);
				uploadThread.start();
			}
			
			try {
				FileUtil.doSerialize(feedSerFile, feedResult);
			} catch (Exception e) {
				throw new RuntimeException(e);
			} finally {

				System.gc();
			}

		} catch (Exception e) {
			throw e;
		}

		return feedResult;
	}

	private static InstaUserInfo getUserInfo(String targetName) throws Exception {
		File userFile = new File(Config.get("path.root")+"/upload/social/insta/_user/"+CryptoUtil.md5(targetName));
		
		InstaUserInfo info = null;
		
		if(userFile.exists()) {
			info = FileUtil.deSerialize(userFile);
			
		} else {

			info = new InstaUserInfo();

			CompletableFuture<UserAction> userActs = client.actions().users().findByUsername(targetName);
			User user = userActs.get().getUser();
			
			info.setUserPk(user.getPk());
			
			InputStream userThumbIn = null;

			try {
				userThumbIn = StreamUtil.getWebStream(user.getProfile_pic_url());
				String fileUrl = user.getProfile_pic_url().replaceFirst("(.*)\\?(.*)", "$1");
				String fileExt = fileUrl.substring(fileUrl.lastIndexOf("."));
				File userThumbFile = new File(Config.get("path.root")+"/upload/social/insta/_user/"+CryptoUtil.md5(targetName)+fileExt);
				FileUtil.writeContent(userThumbIn, userThumbFile);
				
				info.setProfileImageUrl("/upload/social/insta/_user/"+CryptoUtil.md5(targetName)+fileExt);
				
				FileUtil.doSerialize(userFile, info);
				
			} catch (Exception e) {
				e.printStackTrace();
			} finally {
				if(userThumbIn!=null) {
					userThumbIn.close();
				}
			}

		}
		
		return info;
	}

	private static <T>T getSerialObject(File serFile) throws Exception {
		T serialObj;
		
		try {
			serialObj = FileUtil.deSerialize(serFile);

			File[] files = FileUtil.findFilesByExt(serFile.getParent(), ".ser", FileUtil.SortType.DATE_ASC);

			if (files.length > 7) {
				for (int i = 0; i < files.length - 3; i++) {
					if (files[i].equals(serFile)) {
						continue;
					}

					files[i].delete();
				}
			}

		} catch (Exception e) {
			File[] arrFile = FileUtil.getChildrenFiles(serFile.getParent(), FileUtil.SortType.DATE_DESC);

			for (File file : arrFile) {

				serialObj = FileUtil.deSerialize(file);
				return serialObj;
			}

			throw e;
		}

		return serialObj;
	}
	
	public static boolean isUploadComplete(String user) {
		return FeedUploadWorker.isComplete(user);
	}
}

class FeedUploadWorker implements Runnable {
	private static DataMap cmap;
	private String user;
	private DataSet uploadSet;
	
	static {
		cmap = new DataMap();
	}
	
	public static boolean isComplete(String user) {
		return cmap.b(user, true);
	}
	
	public FeedUploadWorker(String user) {
		uploadSet = new DataSet();
		this.user = user;
	}
	
	public void add(String pictureHttpUrl, File file) {
		uploadSet.addRow();
		uploadSet.put("url", pictureHttpUrl);
		uploadSet.put("file", file);
	}
	
	@Override
	public void run() {
		uploadSet.first();
		cmap.put(user, false);
		
		while(uploadSet.next()) {
			
			String pictureHttpUrl = uploadSet.getRow().s("url");
			File file = (File)uploadSet.getRow().get("file");
			
			InputStream in = null;
			try {
				in = StreamUtil.getWebStream(pictureHttpUrl);
				FileUtil.writeContent(in, file);
				
				if (in != null) {
					in.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
		
		cmap.put(user, true);
		
	}
	
	public int size() {
		return uploadSet.size();
	}
}

class InstaUserInfo implements Serializable {
	private static final long serialVersionUID = 671723062770310318L;
	
	private String profileImageUrl;
	private Long userPk;
	public String getProfileImageUrl() {
		return profileImageUrl;
	}
	public void setProfileImageUrl(String profileImageUrl) {
		this.profileImageUrl = profileImageUrl;
	}
	public Long getUserPk() {
		return userPk;
	}
	public void setUserPk(Long userPk) {
		this.userPk = userPk;
	}
}

 

호출할 때마다 인스타그램에 접속하면 나중에 접속제한에 걸리므로,

일정한 시간 단위로 호출하되 이미지와 텍스트는 따로 DB나 직렬화 파일에 저장하는 것을 추천.

package common.util.api;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Locale;

import org.apache.taglibs.standard.tag.common.fmt.LocaleUtil;
import org.json.simple.JSONObject;

import common.util.StringUtil;
import common.util.stream.StreamUtil;
import common.util.stream.StreamUtil.MethodType;
import mvc.Config;
import mvc.model.DataMap;

public class NaverPapago {
	
	private static String API_URL;
	private static String KEY;
	private static String SECRET;

	public static void setting() {
		if(API_URL==null) {
			API_URL = "https://openapi.naver.com/v1/papago/n2mt";
		}
		
		if(KEY==null) {
			KEY = Config.get("keys.naver-papago.key");
		}
		
		if(SECRET==null) {
			SECRET = Config.get("keys.naver-papago.secret");
		}
	}
	
	public static String translate(Locale srcLang, Locale trgLang, String text) throws UnsupportedEncodingException {
		setting();
		
		String message = URLEncoder.encode(text, "utf-8");
		DataMap param = new DataMap();
		param.put("text", message);
		param.put("source", srcLang.getLanguage());
		
		if(StringUtil.isEmpty(trgLang.getLanguage())) {
			return text;
		}
		
		param.put("target", trgLang.getLanguage());
		
		DataMap header = new DataMap();
		header.put("X-Naver-Client-Id", KEY);
		header.put("X-Naver-Client-Secret", SECRET);
		
		JSONObject result = StreamUtil.getWebJson(API_URL, param, MethodType.POST, header);
		DataMap resultMessage = new DataMap(result.get("message"));
		DataMap data = new DataMap((Object)resultMessage.get("result"));
		
		if(data.isEmptyData("translatedText")) {
			trgLang = LocaleUtil.parseLocale("en_US");
			return translate(srcLang, trgLang, text);
		}
		
		return data.s("translatedText");
	}
	
	public static void main(String[] args) {
		try {
			String transText = translate(Locale.KOREA, Locale.ENGLISH, "안녕하세요");
			System.out.println(transText);
		} catch (UnsupportedEncodingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

}

파파고 번역 로직.

하루에 1만 단어 번역이 가능하니 일정한 포맷을 만들어 놓고,

DB나 파일에 저장해서 사용할 수 있다.

'개발이야기 > java' 카테고리의 다른 글

개인정보 (이름) 마스킹 로직  (0) 2022.01.18
Instagram4j 구현  (0) 2022.01.17
Instagram4j - Maven Dependency  (0) 2022.01.14
x진법 (최대 62진수) 까지 표현해주는 함수  (0) 2022.01.14
정렬 - Selection Sort  (0) 2022.01.13

<dependency> 
  <groupId>com.github.instagram4j</groupId>
  <artifactId>instagram4j</artifactId>
  <version>2.0.4</version>
</dependency>

package common.util;

import java.text.DecimalFormat;
import java.util.Random;

/**
 * 숫자 관련 Util
 * @apiNote 숫자 관련 Util
 * @since 2020-01-01
 * @author 청록비
 * @version 2020-01-31 
 */
public class NumberUtil {
	
    public static final char[] digits = {
        '0' , '1' , '2' , '3' , '4' , '5' , '6' , '7' , '8' , '9' , 
        'a' , 'b' , 'c' , 'd' , 'e' , 'f' , 'g' , 'h' , 'i' , 'j' , 
        'k' , 'l' , 'm' , 'n' , 'o' , 'p' , 'q' , 'r' , 's' , 't' ,
        'u' , 'v' , 'w' , 'x' , 'y' , 'z' , 'A' , 'B' , 'C' , 'D' , 
        'E' , 'F' , 'G' , 'H' , 'I' , 'J' , 'K' , 'L' , 'M' , 'N' , 
        'O' , 'P' , 'Q' , 'R' , 'S' , 'T' , 'U' , 'V' , 'W' , 'X' , 
        'Y' , 'Z'
    };
    
    public static String numberToBase(long num, int radix) {
        
    	if(radix > digits.length) {
    		radix = 10;
    	}
    	
    	long mod = 0;
    	StringBuffer rtnValue = new StringBuffer();
    	
    	while(num > 0) {
    		mod = num % (long)radix;
    		num = num / radix;
    		
   			rtnValue.append(digits[(int)mod]);
    	}
    	
    	return rtnValue.reverse().toString();
    }
}

<Selection Sort>

<서론>

내가 프로그래밍 로직에 눈 뜨게 해준 소중한 알고리즘이다.

 

물론 자바를 배우는 지금은 동적할당인 Vector 클래스를 이용해서

Sort() 메소드만 사용하면 단 한 줄 만으로 Sort가 되지만 중요한건

프로그래밍 로직을 이해하기 위해 만들어 보는 것이다.

 

 

<본론>

우선 처리순서와 어떠한 알고리즘으로 돌아가는지 간단히 생각해보자.

Selection Sort는 Sort 중에 가장 단순하면서 가장 느린 Sort이다.

 

첫번째 자리부터 일일이 하나하나 찾아가서 조건이 맞으면 큰 수를

오른쪽으로 보내는 로직이다. 그럼 일단 왼쪽 오른쪽 바꾸는 로직이 필요하겠군.

 

변수 : a[배열], temp

연산자 : >  (왼쪽이 크면)

 

실행문

-  temp = a[i]

    a[i] = a[j]

    a[j] = temp

또는

- a[i] ^= a[j]

    a[j] ^= a[i]

    a[i] ^= a[j]

 

(배열 좌측과 우측을 뒤바꾸는 실행문)

 

클래스 : System.in, Scanner 등등

 

우선 임의의 수 5개를 적어보자.

1004, 40, 486, 50, 20

 

 Selection Sort는 일일이 하나하나 비교하는 거니깐..

1004와 40을 비교하고.. 다음은 1004와 486을 비교, 다음 50, 20 이렇게 비교..

그럼 1부터 5까지 실행하는 제어문이 필요하겠군.. 만만한게 for 다..

 

for(int i=0; i<5; i++) {

처리

}

 

뭐 요런 형태겠군.. 근데 하나로는 안될 거고..

for(int i=0; i<5; i++) {

    for(int j=i; j<5; j++) {

    }

}

이렇게 처리해야겠지?

 

아참... 근데 (1번째) > (1번째)가 아니라 (1번째) > (2번째) 부터 시작을 해야 되고

마지막엔 (4번째) > (5번째) 로 비교를 끝내야 하니까 옵션을 좀더 주면

 

for(int i=0; i<5-1; i++) {

    for(int j=i+1; j<5; j++) {

    }

}

 

대략 이정도가 되겠군... 일단은 생각했던걸 적어보자..

 

int a[] = {1004, 40, 486, 50, 20};
int temp;
for(int i=0; i<a.length-1; i++) {
    for(int j=i+1; j<a.length; j++) {
        if(a[i] > a[j]) {
            temp = a[i];
            a[i] = a[j];
            a[j] = temp;
        }
    }
}
for(int i : a) {
    System.out.print(i + "  ");
}

 

야호~ 다 만들었다~

+ Recent posts