Redis-cli 원격 접속하기.

|

리눅스 데스크탑 매니저 파일이 없어도 외부에서 redis-cli 명령어로 접근이 가능하다는 것을 이제야 알았다…왜 이제 알았을까

1. redis 설치 (windows)

  • https://github.com/rgl/redis/downloads 에서 설치파일 내려받고 설치하면 Program Files 에 설치됨.
  • [2026년 추가] 이 링크는 이제 접근이 안 될 가능성이 높다 — GitHub의 “Downloads” 기능 자체가 오래전에 없어졌다. 애초에 Redis는 공식적으로 Windows를 지원하지 않으므로, 요즘은 WSL2에 리눅스용 Redis를 설치하거나 docker run -d -p 6379:6379 redis 로 띄우는 걸 권장한다.

2. 리눅스에 Redis 설치 (ubuntu)

먼저 리눅스에 redis를 설치하기 위해서 파일을 직접 다운받거나 apt-get 등을 이용할 수 있다. 만약 apt-get 패키지 다운로드를 사용할 경우 아래와 같이 커맨드를 입력하면 된다.

  $ sudo apt-get install redis-server

3. 명령어

  redis-cli -h 123.123.123.123(레디스 설치되어있는 아이피) -p 6379 -a password

-h : 호스트 아이피

-p : redis 포트

-a : 비밀번호

[2026년 추가] -a 로 비밀번호를 커맨드에 그대로 넣으면 쉘 히스토리(~/.bash_history 등)와 그 순간의 프로세스 목록(ps aux로 다른 사용자도 볼 수 있음)에 비밀번호가 그대로 남는다. redis-cli도 이 점을 인지해서 -a 사용 시 경고 메시지를 띄워준다. -a 없이 redis-cli -h ... -p ... 로 접속하면 대화형으로 비밀번호를 물어보거나, 스크립트에서는 REDISCLI_AUTH 환경변수로 넘기는 게 더 안전하다.

더 근본적으로, Redis 인스턴스를 인증 없이(또는 기본 설정 그대로) 외부에 노출해두면 실제로 랜섬웨어 공격의 표적이 된 사례가 많았다 — “원격 접속이 된다”는 것 자체보다, 그 포트가 인터넷에 얼마나 열려 있는지(방화벽/보안그룹으로 필요한 IP만 허용했는지)가 훨씬 중요한 점검 포인트다.

출처:

  • https://blog.geun.kr/349 [Geun`s Page]

[Spring] 스프링에서 File객체를 MultipartFile로 변환하기.

|

스프링에서 파일을 업로드 하려고 하는데, MultipartFile로 업로드를 해야만 하고 File로만 받아올 수 있는 상황이 백엔드에서 파일 다루다 보면 종종 발생한다. 그래서 File > MultipartFile 변환을 해 주어야 하는데 방법을 찾기가 쉽지는 않았다.

일반적이진 않지만 몇가지 방법이 있어 소개한다.

1. 스프링 테스트의 MockMultipartFile 사용

import org.springframework.mock.web.MockMultipartFile;
....

MultipartFile multipartFile = new MockMultipartFile("test.xlsx", new FileInputStream(new File("/home/admin/test.xlsx")));

or

import org.springframework.mock.web.MockMultipartFile;
....
String writerData = "str1,str2,str3,str4";
MultipartFile multipartFile = new MockMultipartFile("files", "파일명.csv", "text/plain", writerData.getBytes(StandardCharsets.UTF_8));

2. IOUtils 사용

1번 방법이 간편하긴 하나.. 테스트를 runtime에 올려햐 하며 사용이 불가능하다는 커뮤니티 글도 있었다.
그럴땐 아래와 같은 방법으로 변환이 가능하다.


File file = new File("/path/to/file");
FileItem fileItem = new DiskFileItem("mainFile", Files.probeContentType(file.toPath()), false, file.getName(), (int) file.length(), file.getParentFile());

try {
    InputStream input = new FileInputStream(file);
    OutputStream os = fileItem.getOutputStream();
    IOUtils.copy(input, os);
    // Or faster..
    // IOUtils.copy(new FileInputStream(file), fileItem.getOutputStream());
} catch (IOException ex) {
    // do something.
}

MultipartFile multipartFile = new CommonsMultipartFile(fileItem);

참고자료

  • https://okky.kr/article/441770
  • https://stackoverflow.com/questions/16648549/converting-file-to-multipartfile

[MyBatis] insert 후 key값 가져오기

|

mybatis 의 insert 구문을 통해 autoincrement 된 키값을 가져오고 싶을 때 사용하는 방법이다.

useGeneratedKeys 옵션

 <insert id="insertData" parameterType="DataClass" useGeneratedKeys="true" keyProperty="id">
     /* query */

 </insert>

id가 autoincrement인 PK일 경우, 그 id값은 DataClass에 선언되어 있는 id 필드 안으로 값이 저절로 들어간다.
debug 찍고 DataClass 객체의 id값을 보면 값이 들어있을 것이다.

selectKey 옵션

Oracle 같은 경우는 Auto Increment 가 없고 Sequence를 사용해야만 한다. 해당 경우엔 아래와 같이 설정해주면 된다.

<insert id="insertStudents" parameterType="DataClass">
  <selectKey keyProperty="id" resultType="int" order="BEFORE">
    select SEQ_ID.nextval FROM DUAL
  </selectKey>
     /* query */
</insert>

참고자료

  • https://marobiana.tistory.com/23 [Take Action]
  • https://taetaetae.github.io/2017/04/04/mybatis-useGeneratedKeys/

[MySQL] 테이블 스키마 정보 조회하기.

|

테이블 필드정보 1

SELECT
 a.TABLE_NAME '테이블명',
 b.ORDINAL_POSITION '순번',
 lower(b.COLUMN_NAME) '필드명',
 upper(b.DATA_TYPE) 'DATA TYPE',
 b.COLUMN_TYPE '데이터길이',
 b.COLUMN_DEFAULT '디폴트값',
 b.COLUMN_KEY 'KEY',
 b.IS_NULLABLE 'NULL값여부',
 b.EXTRA '자동여부',
 b.COLUMN_COMMENT '필드설명'
from information_schema.TABLES a JOIN information_schema.COLUMNS b on a.TABLE_NAME = b.TABLE_NAME and a.TABLE_SCHEMA = b.TABLE_SCHEMA
where a.TABLE_SCHEMA = '테이블 스키마명' 
ORDER BY
  a.TABLE_NAME, b.ORDINAL_POSITION
;

테이블 필드정보 2

SELECT 
  b.TABLE_NAME,
  b.ORDINAL_POSITION,
  lower(b.COLUMN_NAME) '필드명',
  upper(b.DATA_TYPE) 'DATA TYPE',
  b.CHARACTER_MAXIMUM_LENGTH,  
  b.COLUMN_DEFAULT,
  CASE WHEN b.IS_NULLABLE = 'NO' THEN 'NOT NULL' ELSE '' END NULLABLE,
  b.COLUMN_COMMENT
FROM information_schema.COLUMNS b
WHERE TABLE_SCHEMA = '테이블 스키마명'
ORDER BY TABLE_NAME, b.ORDINAL_POSITION
;

인덱스 정보 (프라이머리 제외)

SELECT TABLE_NAME, INDEX_NAME, GROUP_CONCAT(COLUMN_NAME SEPARATOR ','), UNIQ
FROM (
	SELECT TABLE_NAME, SEQ_IN_INDEX, INDEX_NAME, LOWER(COLUMN_NAME) COLUMN_NAME, CASE WHEN NON_UNIQUE = 0 THEN 'UNIQUE' ELSE '' END UNIQ 
	FROM INFORMATION_SCHEMA.STATISTICS
) AS DT
WHERE INDEX_NAME <> 'PRIMARY'
GROUP BY TABLE_NAME, INDEX_NAME, UNIQ
ORDER BY TABLE_NAME
;

테이블 코멘트 조회

SELECT TABLE_NAME, TABLE_COMMENT from information_schema.TABLES
WHERE TABLE_SCHEMA = '테이블 스키마명'
ORDER BY TABLE_NAME
;

HandlerMethodArgumentResolver 를 통해 특정 Argument 사용 시 변경하기.

|

  • HandlerMethodArgumentResolver 를 사용하여 컨트롤러 메소드에 선언된 특정 Arguments를 변경하거나 또는 권한체크를 하여 arguments에 값을 넣어주거나 할 수 있다.

[2026년 추가] 이 글에서 쓴 WebMvcConfigurerAdapter는 Spring 5(2017년)부터 deprecated 되었고, Spring 6부터는 아예 삭제되어 더 이상 컴파일도 안 된다. 자바 8부터 인터페이스에 기본 구현(default method)을 넣을 수 있게 되면서, 모든 메서드를 구현할 필요 없이 필요한 메서드만 오버라이드하도록 도와주던 이 어댑터 클래스 자체가 필요 없어졌기 때문이다. 지금은 WebMvcConfigurer 인터페이스를 바로 구현하면 된다 — 아래 2번 항목의 코드만 그렇게 바꾸면 이 글의 나머지 내용은 최신 Spring Boot에서도 그대로 유효하다.

0. 멤버 클래스


@Getter
@RequiredArgsConstructor
public class Member {
  private final String username;
  private final String email;
}

1. MemberHandlerMethodArgumentResolver 추가.

  1. 컨트롤러에서 파라미터를 바인딩.
    • ex) 특정클래스나 특정 어노테이션등의 요청 파라미터를 수정해야한다거나 또는 클래스의 파라미터를 조작, 혹은 공통적으로 써야하는 파라미터들을 바인딩 해주는 역할을 한다.
    • 예제에서는 유저정보를 고정으로 가져와서 파라미터로 쓰기 위해 사용하였다.
@Slf4j
public class MemberHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver {

    /**
     * @param parameter
     * @return
     */
    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return Member.class.isAssignableFrom(parameter.getParameterType());
    }

    /**
     * @param parameter
     * @param mavContainer
     * @param webRequest
     * @param binderFactory
     * @return
     * @throws Exception
     */
    @Override
    public Member resolveArgument(MethodParameter parameter,
                                  ModelAndViewContainer mavContainer,
                                  NativeWebRequest webRequest,
                                  WebDataBinderFactory binderFactory) throws Exception {

        // 컨트롤러의 메소드에 아래 아규먼트가 선언되었을 때만 아래 로직 태움..
        if (parameter.getParameterType().equals(Member.class)) {
           Member member = new Member("jmlim", "hackerljm@naver.com");
           return member;
        }
    }
}

2. WebConfig에 작성한 ArgumentResolver 등록

// (2026년 수정) WebMvcConfigurerAdapter 대신 WebMvcConfigurer 인터페이스를 직접 구현
@Configuration
public class WebConfig implements WebMvcConfigurer {
  
  @Override
  public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
    argumentResolvers.add(new MemberHandlerMethodArgumentResolver());
  }
}

3. 컨트롤러에서 사용.

Member 클래스에는 아무 파라미터를 넣지 않아도 테스트를 해보면 위에서 넣어둔 jmlim과 hackerljm@naver.com 이 나오게 된다.


@Slf4j
@RestController
@RequestMapping()
public class TestController {


    /**
     *
     * @param member
     * @return
     */
    @GetMapping("/member/info")
    public ResponseEntity getLoginInfo(Member member) {
       /**해당 메소드 호출 전에 resolveArgument 를 타게 됨.*/
       ....
    }

참고:

  • http://wonwoo.ml/index.php/post/1092