반응형

1. cd 디렉터리 변경

2. pwd 현재 디렉터리 절대 경로 표시

3. ls 디렉터리 정보 조사

ls -l 상세정보

ls -a 숨긴 파일까지 보기

 

4. cat 파일 열기

5. grep 여러 파일 중 문자열 검색

grep abc test : test파일의 abc문자열이 포함된 것 검색

 

6. vi

실행 vi sample.txt

종료 esc키 > :q!

 

i - insert 모드 (esc)

: - ex모드

 

:w @저장

:w 파일명  @다름이름으로 저장

:w! @강제 저장

:q @파일 저장하지 않고 저장

:wq @파일 저장 후 종료

 

7. 현재 디렉토리의 모든 폴더, 파일을 755로 권한 변경

chmod 755 ./*

 

1. sort test.txt 텍스트 파일 내용 정렬 

-r 역순

 

2. find namelist 현재 디렉터리의 파일 검색(닷 파일도 가능)

find data namelist : 지정 디렉터리 아래를 대상으로 검색

 

*와일드 카드 사용 가능 (find a*, find a?)

 

3. which / whereis

반응형
반응형

postgresql에는 Oracle의 BLOB 형타입이 없다. 바이너리 데이터를 다룰려면 BYTEA 형타입을 사용해야 함.

 

1. TEXT 타입에 base64 데이터 다운로드

public static void downloadFile(HttpServletResponse response, FileVO file) {

		String fileName = file.getFile_name();
		String base64String = file.getFile_text();
		
		// Base64 인코딩된 데이터에서 "data:image/jpeg;base64," 부분을 제거
        String base64Data = base64String.substring(base64String.indexOf(",") + 1);

        // Base64 문자열을 바이너리 데이터로 디코딩
        byte[] binaryData = Base64.getDecoder().decode(base64Data);
        
        try {
            response.setContentType("application/octet-stream");
            response.setHeader("Content-Disposition", "attachment; filename=\"" + URLEncoder.encode(fileName,"UTF-8") + "\"");
            OutputStream outputStream = response.getOutputStream();
            outputStream.write(binaryData);
            outputStream.flush();
            outputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        
}

 

2. BYTEA 타입에 바이너리 데이터 다운로드

public static void downloadFile(HttpServletResponse response, FileVO file) {

		String fileName = file.getFile_name();
        byte[] binaryData = file.getFile_contents();
        
        try {
            response.setContentType("application/octet-stream");
            response.setHeader("Content-Disposition", "attachment; filename=\"" + URLEncoder.encode(fileName,"UTF-8") + "\"");
            OutputStream outputStream = response.getOutputStream();
            outputStream.write(binaryData);
            outputStream.flush();
            outputStream.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        
}

 

+) VO

public class FileVO {
    private byte[] file_contents;
    private String file_text;

	~~
    
}

 

++) JPA Entity에서 bytea 타입 쓸 경우 

@Entity
@Table(name="tops_file_test")
@Getter @Setter
public class FileEntity {

    @Id
    private String FILE_ID;

    @Column(name = "file_name")
    private String file_name;

    @Type(type="org.hibernate.type.BinaryType")
    @Column(name = "file_contents", columnDefinition="bytea")
    private byte[] file_contents;

}

 

 

*파일 업로드는 MDN 참고해서 result 값을 insert 시키면 된다.

 

<핵심>

new FileReader();

fr.result 

readAsDataURL();

// Given this HTMLInputElement of type="file":
// <input id="image" type="file" accept="image/*">

function reader(file, callback) {
  const fr = new FileReader();
  fr.onload = () => callback(null, fr.result);
  fr.onerror = (err) => callback(err);
  fr.readAsDataURL(file);
}

document.querySelector("#image").addEventListener("change", (evt) => {
  // No files, do nothing.
  if (!evt.target.files) {
    return;
  }
  reader(evt.target.files[0], (err, res) => {
    console.log(res); // Base64 `data:image/...` String result.
  });
});

https://developer.mozilla.org/en-US/docs/Web/API/FileReader/result


서버에 저장된 FILE들을 바이너리 데이터로 변환하여 DB 저장

모두 SEELCT해서 for문 돌리면서 실 파일 데이터를 바이너리 데이터로 변환하여 DB에 저장

(위의 다운로드 코드로 DB SELECT해서 바이너리 데이터를 다운처리 가능)

 

나는 DB 용량 때문에 서버 경로에 저장하는게 괜찮다고 생각하지만 ,, 요구사항이 이렇다!

@RequestMapping("/fileTest")
    public void fileTest (HttpServletResponse response){
        String filePath = "C:/file_test/";

        for (FileEntity file : fileRepository.findAll()) {
            byte[] bytes = FileUtil.FileToData(filePath+file.getFILE_ID());
            file.setFile_contents(bytes);

            fileRepository.save(file);
        }

       // FileUtil.downloadFile(response, bytes);
    }
public static byte[] FileToData(String filePath) {
        byte[] fileBytes = null;
        try {
            InputStream inputStream = new FileInputStream(new File(filePath));

            fileBytes = inputStream.readAllBytes();

            System.out.println("File saved to database.");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return fileBytes;
    }
반응형
반응형

어찌보면 간단한 파일 migration 과업을 할당받았다. 

기존 웹 프로젝트 내부에 작동시키기 보다 연결 DB가 다르고 마이그레이션 특성상 1회성으로 필요한 프로젝트이므로 독립 프로젝트로 생성했다.

 

프레임워크를 붙이지 않고 했다가 서버나 DB연결의 용이성을 위해 붙이게 됐다.

공부할 겸 JPA와 React.js도 한번 붙여보았다. (서버에만 돌아가면 되지만 새로운 것을 공부해보고 싶은 소망.)


개발환경 

  • OS : window10
  • IDE : IntelliJ
  • FrontEnd : HTML/CSS, JavaScript, React.js
  • BackEnd : Spring Boot(Gradle), Spring Data JPA, JAVA11
  • DB : Oracle, Postgresql

 

1. 프로젝트 생성

 

Spring initializr (https://start.spring.io/)

 

*Spring boot 3.X.X 버전이라면 Java17 이상을 사용해야 한다.

*Dpendencies JPA 넣었다가 빌드 해본 후 설정을 쌓아가려고 삭제함.

 

2. IntelliJ 환경설정

[Setting - Build - Gradle] 에서 intelliJ IDEA에서 빌드되도록 수정하고

자바 버전에 맞는 JDK를 설정해주어야 정상적으로 빌드가 된다.

 

Unsupported class file major version 64

위와 같은 오류가 뜨면 JDK가 제대로 설정되어 있는지 확인 필요. 실제로 타 프로젝트 때문에 JDK 17로 설정되어 있어서 오류가 생겼다.

 

 

3. 빌드 한번 해보기

성공

 

4. react.js 설치
React를 개발하기 위해선 Node.js 가 반드시 필요 (npm 명령어로 쓸건데 노드에 들어있기 때문에)

충격,,이래서 리액트 + 노드 조합을 많이 쓰는구나

 

- Node.js 설치

https://nodejs.org/en

 

Node.js

Node.js® is a JavaScript runtime built on Chrome's V8 JavaScript engine.

nodejs.org

 

- react 프로젝트 생성 (터미널)

cd C:\projects\project\src\main
npx create-react-app frontend

Happy hacking!

 

5. DB 연결

- Build.gradle JPA 디펜더시 추가

dependencies {
	implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
}

 

- src/main/resources/application.properties

server.port=8200

## database
spring.datasource.driver-class-name=org.postgresql.Driver
spring.datasource.url=jdbc:postgresql://172.21.71.28:5432/DEV
spring.datasource.username=toutsc_sec
spring.datasource.password=twayOUTSC_sec135!#%

## jpa
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=create
# 쿼리 가독성 향상
spring.jpa.properties.hibernate.format_sql=true
# 쿼리 출력
spring.jpa.properties.hibernate.show_sql=true
# 파라미터 바인딩
logging.level.org.hibernate.type.descriptor.sql=trace
spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation=true

## logging
logging.level.org.hibernate.sql=debug
logging.level.org.hibernate.type.descriptor.sql.spi=trace

* 다른 프로젝트에 8080을 써서 포트 번호 변경

 

또 실행시켜보기. 정상적으로 히카리 풀이 붙었다.

8200포트로 로컬로 접속도 됨.

 

6. react.js와 스프링 연동

 

터미널에서 react 실행

cd frontend
npm start

 

* React 프로젝트 : 3000번 포트

* SpringBoot 프로젝트 : 8080번 포트로 실행

 

- CORS 문제 발생 > proxy 설정

"proxy": "http://localhost:8200"

- Build.gradle

def frontendDir = "$projectDir/src/main/frontend"

sourceSets {
	main {
		resources { srcDirs = ["$projectDir/src/main/resources"]
		}
	}
}

processResources { dependsOn "copyReactBuildFiles" }

task installReact(type: Exec) {
	workingDir "$frontendDir"
	inputs.dir "$frontendDir"
	group = BasePlugin.BUILD_GROUP
	if (System.getProperty('os.name').toLowerCase(Locale.ROOT).contains('windows')) {
		commandLine "npm.cmd", "audit", "fix"
		commandLine 'npm.cmd', 'install' }
	else {
		commandLine "npm", "audit", "fix" commandLine 'npm', 'install'
	}
}

task buildReact(type: Exec) {
	dependsOn "installReact"
	workingDir "$frontendDir"
	inputs.dir "$frontendDir"
	group = BasePlugin.BUILD_GROUP
	if (System.getProperty('os.name').toLowerCase(Locale.ROOT).contains('windows')) {
		commandLine "npm.cmd", "run-script", "build"
	} else {
		commandLine "npm", "run-script", "build"
	}
}

task copyReactBuildFiles(type: Copy) {
	dependsOn "buildReact"
	from "$frontendDir/build"
	into "$projectDir/src/main/resources/static"
}

- project root로 가서 빌드

./gradlew build

 

나는 무슨 삽질을 하고 있었던거지 빌드 안된다고 2시간째 환경변수만 팠네..........

setting에서 jdk고 sdk고 랭기지 버전이고 다 11로 맞췄는데 안돼서 죽어가고 있었는데

인텔리제이 다시 깔고 빌드하고 뭐하니깐 갑자기 됨. 앗솨 됐음 됐어.

 

반응형
반응형
poperty or field 'orderItems' cannot be found on object of type

orderItems를 getter를 못해서 생김

 

나의 경우는 황당하게 

getter, public도 다 되어있지만

Order 엔티티 Class의 orderItems의 필드가 orderitems로 오타가 있어서 못불러왔다.

반응형
반응형

DB계정이 두개인데 계속 있는 권한이나 테이블이 없다그래서 프로젝트 다 까봄

 

context-datasource.xml

 

1) bean

<bean id="datasourceId" class="!!class!!" destroy-method="close">
    <property name="uniqueResourceName" value="datasourceId" />
    <property name="xaDataSourceClassName" value="!!className!!" />
    <property name="xaProperties">
        <props>
            <prop key="URL">${jdbc.pj.url}</prop>
            <prop key="user">${jdbc.pj.username}</prop>
            <prop key="password">${jdbc.pj.password}</prop>
        </props>
    </property>
</bean>

 

2) entry key 작성

<bean id="datasources" class="~~">
    <property name="targetDataSources">
        <map key-type="java.lang.String">
            <entry key="default" value-ref="datasourcePost" />
            <entry key="sub" value-ref="datasourceOracle" />
        </map>
    </property>
</bean>

 

sql-mapper-config.xml

 

* databaseIdProvider에 name 추가

*entry key랑 맞춰주쇼

<databaseIdProvider type="DB_VENDOR">
    <property name="main" value="PostgreSQL" />
    <property name="sub" value="Oracle" />
</databaseIdProvider>

얏호 해결!

 

https://mybatis.org/mybatis-3/ko/configuration.html

마이바티스 매뉴얼에도 나와있다.

DB_VENDOR 설정하기

반응형
반응형

 

- 파라미터가 다 있을 때

    public List<Order> findAll(OrderSearch orderSearch) {
        return em.createQuery("select o from Order o join o.member m" +
                        "where o.status :=status " +
                        "and m.name like :name", Order.class)
                .setParameter("status", orderSearch.getOrderStatus())
                .setParameter("name", orderSearch.getMemeberName())
                .setMaxResults(1000)   // 최대 1000건
                .getResultList();
    }

 

- 동적쿼리 

 

1) JPQL로 처리 

코드도 길고 유지보수하기 힘들다. 실무에서 안씀!

    public List<Order> findAllByString(OrderSearch orderSearch) {

        String jpql = "select o from Order o join o.member m";
        boolean isFirstCondition = true;

        //주문 상태 검색
        if (orderSearch.getOrderStatus() != null) {
            if (isFirstCondition) {
                jpql += " where";
                isFirstCondition = false;
            } else {
                jpql += " and";
            }
            jpql += " o.status = :status";
        }

        //회원 이름 검색
        if (StringUtils.hasText(orderSearch.getMemberName())) {
            if (isFirstCondition) {
                jpql += " where";
                isFirstCondition = false;
            } else {
                jpql += " and";
            }
            jpql += " m.name like :name";
        }

        TypedQuery<Order> query = em.createQuery(jpql, Order.class)
                .setMaxResults(1000);

        if (orderSearch.getOrderStatus() != null) {
            query = query.setParameter("status", orderSearch.getOrderStatus());
        }
        if (StringUtils.hasText(orderSearch.getMemberName())) {
            query = query.setParameter("name", orderSearch.getMemberName());
        }
        return query.getResultList();
    }

 

2) JPA Criteria로 처리

JPA 표준 제공(JPA 스펙에 있어서 실습 진행한 것이 실무에 사용되는 것은 아니다.)

1번보다 짧아졌지만 이 코드만 봐서 무슨 쿼리가 생성되는지 모르겠음 > 유지보수가 힘들다.

    public List<Order> findAllByCriteria(OrderSearch orderSearch){
        //jpa 표준 제공
        CriteriaBuilder cb = em.getCriteriaBuilder();

        CriteriaQuery<Order> cq = cb.createQuery(Order.class);
        Root<Order> o = cq.from(Order.class);
        Join<Order, Order> m = o.join("member", JoinType.INNER);

        List<Predicate> criteria = new ArrayList<>();

        // 주문 상태 검색
        if(orderSearch.getOrderStatus() != null) {
            Predicate status = cb.equal(o.get("status"), orderSearch.getOrderStatus());
            criteria.add(status);
        }

        //회원 이름 검색
        if (StringUtils.hasText(orderSearch.getMemberName())) {
            Predicate name =
                    cb.like(m.<String>get("name"), "%" +
                            orderSearch.getMemberName() + "%");
            criteria.add(name);
        }
        cq.where(cb.and(criteria.toArray(new Predicate[criteria.size()])));
        TypedQuery<Order> query = em.createQuery(cq).setMaxResults(1000); //최대 1000건

        return query.getResultList();
    }

 

3) Querydsl로 처리(강추!!)

JAVA 코드이기 때문에 오류가 나면 확인 가능(실수 방지)

*추후에 보충 수정 예정!

 

반응형
반응형

1. try~catch문

   @Test
    public void 중복_회원_예외() throws Exception {
        //given
        Member member1 = new Member();
        member1.setName("kim");

        Member member2 = new Member();
        member2.setName("kim");

        //when
        memberService.join(member1);
        try {
            memberService.join(member2);    // 예외 발생
        } catch(IllegalStateException e) {
            return;
        }

        //then
        fail("예외가 발생해야 한다.");
    }

 

2. @Test(expected = )

    @Test(expected = IllegalStateException.class)
    public void 중복_회원_예외() throws Exception {
        //given
        Member member1 = new Member();
        member1.setName("kim");

        Member member2 = new Member();
        member2.setName("kim");

        //when
        memberService.join(member1);
        memberService.join(member2);    // 예외 발생

        //then
        fail("예외가 발생해야 한다.");
    }

 

 

인프런 실전! 스프링 부트와 JPA 활용 1 - 회원서비스 테스트

반응형
반응형
  • persist는 DB에 바로 저장되지 않고 commit이 하는 순간 JPA 영속성 콘텍스트가 있는 멤버객체가 insert문이 만들어짐
  • Transactional : rollback 하기 때문에 commit 해서 DB결과를 볼 수 있음

 

1. @Rollback(false) - commit됨

@RunWith(SpringRunner.class)    // 순수 단위테스트가 아닌 DB까지 JPA가 돌아가는 과정을 테스트하기 위함
@SpringBootTest
@Transactional
public class MemberServiceTest {

    @Autowired MemberService memberService;
    @Autowired MemberRepository memberRepository;

    @Test
    @Rollback(false)
    public void 회원가입() throws Exception {
        //given
        Member member = new Member();
        member.setName("kim");

        //when
        Long joinedId = memberService.join(member);

        //then
        assertEquals(member, memberRepository.findOne(joinedId));
    }
 }

 

2. em.flush(); - insert DB반영되지만 rollback됨

@RunWith(SpringRunner.class)    // 순수 단위테스트가 아닌 DB까지 JPA가 돌아가는 과정을 테스트하기 위함
@SpringBootTest
@Transactional
public class MemberServiceTest {

    @Autowired MemberService memberService;
    @Autowired MemberRepository memberRepository;
    @Autowired EntityManager em;

    @Test
    public void 회원가입() throws Exception {
        //given
        Member member = new Member();
        member.setName("kim");

        //when
        Long joinedId = memberService.join(member);

        //then
        em.flush();
        assertEquals(member, memberRepository.findOne(joinedId));
    }
 }

 

 

인프런 실전! 스프링 부트와 JPA 활용 1 - 회원서비스 테스트

반응형