https://www.acmicpc.net/problem/1919

 

1919번: 애너그램 만들기

두 영어 단어가 철자의 순서를 뒤바꾸어 같아질 수 있을 때, 그러한 두 단어를 서로 애너그램 관계에 있다고 한다. 예를 들면 occurs 라는 영어 단어와 succor 는 서로 애너그램 관계에 있는데, occurs

www.acmicpc.net

 

Sol 1)

문제 조건을 보면 소문자가 주어지니까 한글자씩 비교하면서, 같은 글자가 존재하면 이를 'A'로 바꿔버린다. 

예를들어, dared와 bread라고 하면

d a r e d

b r e a d

A A A A d

b A A A A

로 바뀌게 되는 것이다. 이제 b,d 두 문자만 남으므로 2개를 제거하는 것이 답이다.

 

a a b b c c

x x y y b b 

이면,

a a A A c c 

x x y y A A

로 바뀌니까 총 8개이다.

 

코드로 작성해보면,

 

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
32
33
34
35
import java.util.Scanner;
 
public class Main {
 
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String str1 = sc.next();
        String str2 = sc.next();
        char[] char1 = str1.toCharArray();
        char[] char2 = str2.toCharArray();
        int cnt = 0;
        for (int i = 0; i < char1.length; i++) {
            for (int j = 0; j < char2.length; j++) {
                if (char1[i] == char2[j]) {
                    char1[i] = 'A';
                    char2[j] = 'A';
                }
            }
        }
        for (int i = 0; i < char1.length; i++) {
            if (char1[i] != 'A') {
                cnt++;
            }
        }
        for (int i = 0; i < char2.length; i++) {
            if (char2[i] != 'A') {
                cnt++;
            }
        }
 
        System.out.println(cnt);
    }
 
}
 
cs

 

 

Sol 2)

애너그램이라는게 결국 알파벳의 종류, 그 개수가 완전히 같은 단어이므로

각 단어에서 어떤 알파벳을 가지고 있고, 각각 몇개씩 가지고 있는지를 비교하도록 한다.

예를들어,

dared: 'a': 1, 'b': 0, 'd': 2, 'e': 1, 'r': 1 이고

bread: 'a': 1, 'b': 1, 'd': 1, 'e': 1, 'r': 1 이다.

알파벳의 종류와 그 개수가 동일하다면 제거할 필요가 없다. 즉 신경쓸 필요가 없다.

종류와 개수가 다른 경우만 체크해주면 된다.

즉, b와 d만 비교해주고, 그 개수의 차이만큼만 제거해주면 된다. (b 1개, d 1개 총 2개)

 

코드로 작성해보자.

 

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
import java.util.Scanner;
 
public class Main {
 
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String str1 = sc.next();
        String str2 = sc.next();
        
        /* 
        알파벳 카운트되는 배열만들기
        index 0 1 2 3 4 5 ... 25
        count 
        알파벳  a b c d e f ... z
        
        int[] arr = new int[26]; 에서
        어떤 단어가 bear이다?
        {1, 1, 0, 0, 1.... } 이런식으로 카운트를 표시!
        
        */
         
        int[] alphaArr1 = new int[26]; // 알파벳 개수(26개)
        for (int i = 0; i < str1.length(); i++) {
            alphaArr1[str1.charAt(i) - 'a']++;
        }
        
        int[] alphaArr2 = new int[26]; // 알파벳 개수(26개)
        for (int i = 0; i < str2.length(); i++) {
            alphaArr2[str2.charAt(i) - 'a']++;
        }
        
        int ans = 0;
        for (int i = 0; i < 26; i++) {
            if(alphaArr1[i] > alphaArr2[i]) {
                ans += alphaArr1[i] - alphaArr2[i];
            }
            else if(alphaArr1[i] < alphaArr2[i]) {
                ans += alphaArr2[i] - alphaArr1[i];
            }
        }
        
        System.out.println(ans);
        
    }
 
}
 
cs

 

위 코드에서 사용된 중요한 생각!

int[ ] arr = new int [ 26 ];을 만드는 부분

그 결과를 아래 그림처럼 생각해라

첫번째 행은 a,b,c...처럼 알파벳의 위치로 생각하는 부분

두번째 행은 초기값은 다 0이지만, 카운트가 되면 1씩 증가시키는 부분

세번째 행은 index number

 

Sol 2-1)

위 코드를 좀 더 간결하게 만들기 위해 함수를 사용해보자.

 

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
import java.util.Scanner;
 
public class Main {
 
    public static int[] get_alphabet_count(String str) {
        int[] count = new int[26];
        for (int i = 0; i < str.length(); i++) {
            count[str.charAt(i) - 'a']++;
        }
        return count;
    }
 
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String str1 = sc.next();
        String str2 = sc.next();
 
        int[] alphaArr1 = get_alphabet_count(str1);
        int[] alphaArr2 = get_alphabet_count(str2);
 
        int ans = 0;
        for (int i = 0; i < 26; i++) {
            ans += Math.abs(alphaArr1[i] - alphaArr2[i]); // 차이 구하기 위해 절댓값 사용
        }
 
        System.out.println(ans);
 
    }
 
}
 
cs

정리에 앞서, Spring Boot에서 file upload 및 download를 위해 작성된 코드는 다음과 같다.

 

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
package mul.cam.a.controller;
 
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.Date;
 
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.InputStreamResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
 
import jakarta.servlet.ServletContext;
import jakarta.servlet.http.HttpServletRequest;
import mul.cam.a.MediaTypeUtiles;
import mul.cam.a.dto.HumanDto;
 
@RestController
public class HelloController {
 
    // file upload
    @RequestMapping(value = "/fileUpload", method = RequestMethod.POST)
    public String fileUpload(HumanDto human,
                             @RequestParam("uploadFile")
                             MultipartFile uploadFile,
                             HttpServletRequest req) {
        
        System.out.println("HelloController fileUpload " + new Date());
        System.out.println(human.toString());
        
        // 경로
        String path = req.getServletContext().getRealPath("/upload"); // 서버에 업로드
//        String path = "c:\temp"; // 폴더에 upload
        
        
        String filename = uploadFile.getOriginalFilename(); // 기본 파일명
        String filepath = path + "/" + filename;
        
        System.out.println(filepath);
        
        File file = new File(filepath);
        try {
            BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file));
            bos.write(uploadFile.getBytes());
            bos.close();
        
        } catch (Exception e) {
            return "file upload fail";
        } 
        return "file upload success";
        
    }
    
    // file download
    @Autowired
    ServletContext servletContext;
    
    @RequestMapping(value = "/fileDownload")
    public ResponseEntity<InputStreamResource> download(String filename, HttpServletRequest req) throws Exception{
        System.out.println("HelloController download " + new Date());
        
        // 경로
        String path = req.getServletContext().getRealPath("/upload");
        
        MediaType mediaType = MediaTypeUtiles.getMediaTypeForFileName(this.servletContext, filename);
        System.out.println("filename: " + filename);
        System.out.println("mediaType: " + mediaType);
        
        File file = new File(path + "/" + filename); // filename은 업로드됐을 때의 new filename
//        File file = new File(path + File.separator + filename);
        
        InputStreamResource isr = new InputStreamResource(new FileInputStream(file));
        
        // db에서 다운로드 카운트 넣으려면 이 곳에 넣음
        
        return ResponseEntity.ok()
                .header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + file.getName()) // file.getName()은 원본 파일명
                .contentType(mediaType)
                .contentLength(file.length())
                .body(isr);
    }
    
    
    
    
}
 
cs

 

위 코드에 사용된 static 함수인 getMediaTypeForFileName을 정의한 클래스는

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package mul.cam.a;
 
import org.springframework.http.MediaType;
 
import jakarta.servlet.ServletContext;
 
public class MediaTypeUtiles {
 
    public static MediaType getMediaTypeForFileName(ServletContext servletContext, String filename) {
        
        String minType = servletContext.getMimeType(filename);
        
        try {
            MediaType mediaType = MediaType.parseMediaType(minType);
            return mediaType;
        } catch (Exception e) {
            return MediaType.APPLICATION_OCTET_STREAM;
        }
        
        
    }
}
 
cs

 

 

이제, React 부분을 살펴보자.

 

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
// Spring Boot의 sample2-file에 맞춰 작성
 
// npm install axios
import React, {useState} from 'react';
import axios from 'axios';
 
function App() {
 
  // HumanDto 부분
  const [number, setNumber] = useState(''); 
  const [name, setName] = useState('');  
  const [address, setAddress] = useState('');   
 
  const numberChange = (e) => setNumber(e.target.value);
  const nameChange = (e) => setName(e.target.value);
  const addressChange = (e) => setAddress(e.target.value);
 
  const onSubmit = (e) => {
    e.preventDefault(); // 기본 기능과 다르게 만드니까
    
    // alert('onSubmit');
 
    // file + form field -> 짐을 싼다
 
    // /fileUpload 부분에 HumanDto 객체를 참조하는 매개변수를 받는 부분이 있어서 작성하는 것
    let formData = new FormData();
    formData.append("number", number);
    formData.append("name"name);
    formData.append("address", address);
 
    // Spring Boot에서 @RequestParam("uploadFile")에 맞춰라
    formData.append("uploadFile"document.frm.uploadFile.files[0]);
 
    // 보내자!
    axios.post("http://localhost:3000/fileUpload", formData)
    .then(res=>// success
      console.log(res.data);
      alert('file upload에 성공했습니다');
    })
    .catch(function(error){ // error
      alert('file upload에 실패했습니다');
    });
 
  }
 
  // download
  const download = async () => {
    let filename = "abc.txt";
 
    // /fileDownload의 매개변수명인 filename에 맞춘다.
    const url = "http://localhost:3000/fileDownload?filename=" + filename;
 
    /*
    // a tag를 생성하고 자동실행
    const download = document.createElement('a'); // <a> 생성
    download.setAttribute('href', url);
    download.setAttribute('download', filename);
    download.setAttribute('type', 'applicaiton/json');
    download.click();
    */
 
    // react에서는 window를 붙여줘야 한다.
    window.location.href = url;
 
  }
 
 
  return (
    <div>
      <h3>file upload</h3>
      
      <form name="frm" onSubmit={onSubmit} encType="multipart/form-data">
        <input value={number} onChange={numberChange} placeholder='번호' /><br/>
        <input value={name} onChange={nameChange} placeholder='이름' /><br/>
        <input value={address} onChange={addressChange} placeholder='주소' /><br/><br/>   
 
        <input type='file' name="uploadFile" accept='*' />
 
        <input type="submit" value="file upload" />
 
      </form>
 
      <hr/>
 
      <h3>file download</h3>
      <button onClick={download}>file download</button>
 
    </div>
  );
}
 
export default App;
 
cs

 

그 결과는

 

 

 

abc.txt라는 파일을 업로드하고, 다운로드 받아보도록 하겠다. (input 태그도 간단하게 입력하고)

 

 

 

 

끝.

 

 

'React' 카테고리의 다른 글

[React] axios  (0) 2023.03.29
[React] session과 cookie  (0) 2023.03.29
[React] hook - useEffect  (0) 2023.03.29
[React] hook - useState  (0) 2023.03.29
[React] 리액트 시작 및 기초  (0) 2023.03.29

Spring Boot에서 간단하게 만들었던 controller를 가지고 axios를 이해해보자.

 

먼저, 과거 만들었던 Spring Boot 부분

 

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
package mul.cam.a.controller;
 
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
 
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
 
import mul.cam.a.dto.HumanDto;
 
@RestController 
// MVC model에서의 @Controller(controller부분) + @Responsebody(ajax부분)
public class HelloController {
 
    /////////////// 서버(back-end)에서 값을 보내주기만 하는 부분 ////////////////////////
    // http://localhost:3000/
    @RequestMapping(value = "/", method = RequestMethod.GET)
    public String hello() {
        System.out.println("HelloController hello() " + new Date());
        
        return "hello"// ajax를 통해 값을 front-end로 보내준다.
    }
    
    // http://localhost:3000/test
    @GetMapping(value = "/test")
    public String test() {
        System.out.println("HelloController test() " + new Date());
        
        return "테스트";
    }
    
    // http://localhost:3000/human
    @GetMapping(value = "/human")
    public HumanDto getDto() {
        System.out.println("HelloController getDto() " + new Date());
        
        HumanDto human = new HumanDto(1001"홍길동""서울시");
        
        return human;
    }
    
    // http://localhost:3000/get_list
    @GetMapping("/get_list")
    public List<HumanDto> get_list(){
        System.out.println("HelloController get_list() " + new Date());
 
        List<HumanDto> list = new ArrayList<>();
        list.add(new HumanDto(101"홍길동""서울시"));
        list.add(new HumanDto(102"성춘향""남원시"));
        list.add(new HumanDto(103"임꺽정""광주시"));
        
        return list;
    }
    
////////////////// 외부에서 데이터를 서버로 보낸 경우, 서버에서 매개변수로 받는 것 /////////////////////
    // 예를 들어, http://localhost:3000/conn_param?title=제목입니다
    @GetMapping(value = "/conn_param")
    public String conn_param(String title) {
        System.out.println("HelloController conn_param() " + new Date());
 
        System.out.println("title: " + title);
        
        return "conn success";
    }
    
    // http://localhost:3000/param_obj?number=1002&name=성춘향&address=남원시
    @GetMapping(value = "param_obj")
    public String param_obj(HumanDto human) {
        System.out.println("HelloController param_obj() " + new Date());
 
        System.out.println("human: " + human);
        
        return "OK";
    }
    
    
    
    
}
 
cs

 

 

axios는 ajax를 대신!!

 

react에서 axios를 사용하기 위해서는 npm install axios를 실행해줘야 한다.

또한, import axios from 'axios'와 같이 import 해줘야 한다.

 

현재 spring boot에서 port number 3000을 사용하고 있으므로, 겹치지 않도록 react의 port number를 미리 변경해주도록 한다.

바꾸는 방법은 package.json 파일에서 

 

 

와 같이 set PORT=포트넘버 && 을 기존 코드 앞에 추가해주면 된다. 

 

Spring Boot의 각 Mapping의 value를 기준으로 나눠서 살펴보자.

 

1. /test

 

Spring Boot 부분

 

1
2
3
4
5
6
7
// http://localhost:3000/test
    @GetMapping(value = "/test")
    public String test() {
        System.out.println("HelloController test() " + new Date());
        
        return "테스트";
    }
cs

 

React 부분

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import React, {useEffect, useState} from "react";
import axios from 'axios';
 
function App(){
 
  const fetchData = async () => {
    const response = await axios.get('http://localhost:3000/test', {} )
    console.log(response.data);
  }
 
  useEffect(()=>{
 
    fetchData();
 
  }, []);
 
  return(
    <div>
      <p>axios</p>
    </div>
  )
}
 
export default App;
cs

 

 

결과

 

 

 

 

2. /human

 

Spring Boot 부분

 

1
2
3
4
5
6
7
8
9
// http://localhost:3000/human
    @GetMapping(value = "/human")
    public HumanDto getDto() {
        System.out.println("HelloController getDto() " + new Date());
        
        HumanDto human = new HumanDto(1001"홍길동""서울시");
        
        return human;
    }
cs

 

React 부분

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import React, {useEffect, useState} from "react";
import axios from 'axios';
 
function App(){
 
  const fetchData = async () => {
    const response = await axios.get('http://localhost:3000/human', {} )
    console.log(response.data);
  }
 
  useEffect(()=>{
 
    fetchData();
 
  }, []);
 
  return(
    <div>
      <p>axios</p>
    </div>
  )
}
 
export default App;
cs

 

 

결과

 

 

 

3. /conn_param

 

1,2번과 다르게 front-end(react)에서 back-end(spring boot)로 값을 넘겨주고, 다시 넘겨받는 구조이다.

즉, 

const response = await axios.get('http://localhost:3000/test', {} ) // 1번

const response = await axios.get('http://localhost:3000/human', {} ) // 2번

에서는 { } 처럼 넘겨주는 값이 없어서 비어있지만,

 

3번에서는 

const response = await axios.get('http://localhost:3000/conn_param', { params: {title:"제목"} } ) 와 같이

{ params: {title:"제목"} }으로 값을 넘겨준다.

이때, title은 매개변수명이므로 spring boot에서의 매개변수명과 맞춰줘야 한다.

 

Spring Boot 부분

 

1
2
3
4
5
6
7
8
9
// 예를 들어, http://localhost:3000/conn_param?title=제목입니다
    @GetMapping(value = "/conn_param")
    public String conn_param(String title) {
        System.out.println("HelloController conn_param() " + new Date());
 
        System.out.println("title: " + title);
        
        return "conn success";
    }
cs

 

React 부분

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import React, {useEffect, useState} from "react";
import axios from 'axios';
 
function App(){
 
  const fetchData = async () => {
    const response = await axios.get('http://localhost:3000/conn_param', { params: {title:"제목"} } )
    console.log(response.data);
  }
 
  useEffect(()=>{
 
    fetchData();
 
  }, []);
 
  return(
    <div>
      <p>axios</p>
    </div>
  )
}
 
export default App;
cs

 

결과

 

 

 

 

 

이제 post 방식으로도 axios를 사용해보자.

 

먼저,  Spring Boot 부분은 아래와 같다.

 

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
package mul.cam.a.controller;
 
import java.util.Date;
import java.util.List;
 
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
 
import mul.cam.a.dto.MemberDto;
import mul.cam.a.service.MemberService;
 
@RestController
public class MemberController {
    
    @Autowired
    MemberService service;
    
    @PostMapping(value = "/allList")
    public List<MemberDto> allList(String user){
        System.out.println("MemberController allList " + new Date());
        
        System.out.println("user: " + user);
        
        return service.allMember();
    }
}
 
cs

 

React 부분

 

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
import React, {useEffect, useState} from "react";
import axios from 'axios';
 
function App(){
 
  const [memberlist, setMemberlist] = useState([]);
 
  // post는 매개변수가 다르다
  // get방식은 2번째 위치에 params가 들어오고,
  // post 방식은 2번째 위치에는 null, 3번째 위치에 params가 들어온다.
  const fetchData = async () => {
  const response = await axios.post('http://localhost:3000/allList'null, { params: {user:"홍길동"} });
  console.log(response.data);
 
  setMemberlist(response.data);
  }
  useEffect(()=>{
 
    fetchData();
 
  }, []);
 
  return(
    <div>
      <h3>axios test</h3>
 
        <table border="1">
          <thead>
            <tr>
              <th>No</th><th>id</th><th>password</th><th>name</th><th>email</th>
            </tr>
          </thead>
          <tbody>
            {
              memberlist.map(function(member, i){
                return (
                  <tr key={i}>
                    <th>{i+1}</th>
                    <td>{member.id}</td>
                    <td>{member.pwd}</td>
                    <td>{member.name}</td>
                    <td>{member.email}</td>
                  </tr>
                )
              })
            }
          </tbody>
 
        </table>
    </div>
  )
}
 
export default App;
cs

 

결과를 보기에 앞서, db에 이미 저장했던 값들이 있어서 아래와 같이 결과가 나타나는 것뿐이지 table 안의 값들은 큰 의미가 없다.

 

 

 

 

이때, react 코드를 아래와 같이 작성할 수도 있다.(table 부분)

 

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
import React, {useEffect, useState} from "react";
import axios from 'axios';
 
function App(){
 
  const [memberlist, setMemberlist] = useState([]);
 
  // post는 매개변수가 다르다
  // get방식은 2번째 위치에 params가 들어오고,
  // post 방식은 2번째 위치에는 null, 3번째 위치에 params가 들어온다.
  const fetchData = async () => {
  const response = await axios.post('http://localhost:3000/allList'null, { params: {user:"홍길동"} });
  console.log(response.data);
 
  setMemberlist(response.data);
  }
  useEffect(()=>{
 
    fetchData();
 
  }, []);
 
  return(
    <div>
      <h3>axios test</h3>
 
        <table border="1">
          <thead>
            <tr>
              <th>No</th><th>id</th><th>password</th><th>name</th><th>email</th>
            </tr>
          </thead>
          <tbody>
          {
            memberlist.map(function(member, i){
              return (
                // <tr key={i}>
                //   <th>{i+1}</th>
                //   <td>{member.id}</td>
                //   <td>{member.pwd}</td>
                //   <td>{member.name}</td>
                //   <td>{member.email}</td>
                // </tr>
 
                <TableRow cnt={i + 1} mem={member} key={i} />
              )
            })
          }
        </tbody>
 
      </table>
    </div>
  );
}
 
function TableRow(props){
  return(
    <tr>
      <th>{props.cnt}</th>
      <td>{props.mem.id}</td>
      <td>{props.mem.pwd}</td>
      <td>{props.mem.name}</td>
      <td>{props.mem.email}</td>
    </tr>
  );
}
 
export default App;
cs

 

 

끝.

'React' 카테고리의 다른 글

[React] file upload & download  (0) 2023.03.30
[React] session과 cookie  (0) 2023.03.29
[React] hook - useEffect  (0) 2023.03.29
[React] hook - useState  (0) 2023.03.29
[React] 리액트 시작 및 기초  (0) 2023.03.29

Theme. session

 

우선, session을 사용하기 위해서 npm install react-session-api 를 실행해줘야 한다.

 

session을 사용하는 예를 3가지 정도 나타내보도록 한다.

 

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
32
import React from 'react';
import Session from 'react-session-api';
 
function App(){
 
  // session 저장하는 함수 정의
  function save(){
    let count = 1024;
    Session.set("counter", count); // Session.set("세션명", 값);
 
  }
 
  // session 불러오는 함수 정의
  function load(){
    let c = Session.get("counter");
    alert(c); // 1024
  }
 
  return(
    <div>
      <h3>session test</h3>
 
      <button onClick={() => save()}>session 저장</button>
 
      <button onClick={() => load()}>session 읽기</button>
 
    </div>
  )
 
}
 
export default App;
cs

 

session 저장, session 읽기 버튼을 순차적으로 클릭한 결과는,

 

 

 

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
32
33
import React from 'react';
import Session from 'react-session-api';
 
function App(){
 
  // session 저장하는 함수 정의
  function save(){
    let member = { "id":"abc""pw":"123"};
    Session.set("member", member); // Session.set("세션명", 값);
 
  }
 
  // session 불러오는 함수 정의
  function load(){
    let member = Session.get("member");
    // alert(member);
    alert(JSON.stringify(member));
  }
 
  return(
    <div>
      <h3>session test</h3>
 
      <button onClick={() => save()}>session 저장</button>
 
      <button onClick={() => load()}>session 읽기</button>
 
    </div>
  )
 
}
 
export default App;
cs

 

 

 

 

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
32
33
import React from 'react';
import Session from 'react-session-api';
 
function App(){
 
  // session 저장하는 함수 정의
  function save(){
    let jsonData = [ { "name":"홍길동""age":24}, { "name":"성춘향""age":16} ];
    Session.set("jsonData", jsonData); // Session.set("세션명", 값);
 
  }
 
  // session 불러오는 함수 정의
  function load(){
    let jsonData = Session.get("jsonData");
    // alert(JSON.stringify(jsonData));
    alert(jsonData[1].age); // 16
  }
 
  return(
    <div>
      <h3>session test</h3>
 
      <button onClick={() => save()}>session 저장</button>
 
      <button onClick={() => load()}>session 읽기</button>
 
    </div>
  )
 
}
 
export default App;
cs

 

 

 

 

 

 

 

Theme. cookie

 

cookie를 사용하기 위해서 npm install react-cookie를 실행해줘야 한다.

 

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
32
33
34
35
import React, {useState} from 'react';
import {useCookies} from 'react-cookie';
 
function App() {
 
  const [id, setId] = useState("");
 
  // 기존의 cookie를 저장
  const [cookies, setCookies] = useCookies(["id"]);
 
  const changeId = (e) => setId(e.target.value);
 
  // cookid 저장하기
  const cookieSave = () => {
    setCookies("id", id, { path:'/' }); // cookie명, 값, 경로
  }
 
  // cookie 불러오기
  const cookieLoad = () => {
    alert(cookies.id);
  }
 
  return (
    <div>
      <h3>cookie test</h3>
 
      <input value={id} onChange={changeId} /><br/>
 
      <button onClick={cookieSave}>cookie 저장</button>
      <button onClick={cookieLoad}>cookie 불러오기</button>
    </div>
  );
}
 
export default App;
cs

 

그 결과는,

 

 

 

과정을 설명하도록 하자.

처음 id의 초기값은 빈칸이다. 그리고 아직 "id"라는 쿠키명으로 저장된 값이 없는 상태.

따라서, cookies의 값도 없다.

하지만, input에 값을 입력하게 되면, 그 값이 changeId라는 함수에 의해 id에 저장된다.  

이후, cookie 저장이라는 버튼을 누르면 cookieSave 함수를 통해 "id"라는 쿠키명으로 변수 id에 저장된 값(입력된 값)이 저장되게 된다. 또한, useCookies에 의해 cookies라는 변수에 쿠키가 저장된다. 

그리고, cookie 불러오기라는 버튼을 누르게 되면, 저장된 cookie가 불러와진다.

 

 

 

끝.

'React' 카테고리의 다른 글

[React] file upload & download  (0) 2023.03.30
[React] axios  (0) 2023.03.29
[React] hook - useEffect  (0) 2023.03.29
[React] hook - useState  (0) 2023.03.29
[React] 리액트 시작 및 기초  (0) 2023.03.29

Theme. useEffect의 case 분류

 

크게 3가지로 나누어 살펴보도록 한다.

1. rendering이 완료될 때마다 실행되는 경우

2. 처음 rendering이 되었을 때만 실행되는 경우(초기화의 기능)

3. 특정 값(변수)이 변경될 때에만 실행되는 경우

 

아래의 각 코드마다 상위에 

import React, { useEffect, useState } from "react";

를 해줘야함을 잊지 말자.

 

Theme. rendering이 완료될 때마다 실행

 주의: 무한 루프에 빠질 수 있음

코드와 함께 살펴보자.

 

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
function App() {
 
  const [count, setCount] = useState(0); // 초기값 0
 
  const CountUp = () => setCount(count + 1); // count++, count+=1 사용 불가능
 
  // useEffect(함수, 배열)
  useEffect(()=>{
    console.log("useEffect!!", count);
  })
 
  return (
    <div>
      <p>count: {count}</p>
      {/* 클릭하면 count가 바뀌어서 화면에 나타난다. 따라서 useEffect 실행됨 */}
      <button onClick={()=>CountUp()}>count 증가</button>
      {/* <button onClick={CountUp}>counter</button> */}
 
      {/* 클릭해도 화면의 변화는 없다 따라서 useEffect 실행 안됨 */}
      <button onClick={()=>{console.log('클릭')}}>클릭</button> 
    </div>
  );
}
 
export default App;
cs

 

처음 실행하면, useEffect가 실행된다.

즉, count의 초기값은 0이므로 console을 확인해보면, 아래와 같이 실행되는 것을 알 수 있다.

 

또한 UI를 보면,

 

 

count가 증가되는 버튼과 단순히 console에 '클릭'이라는 단어가 찍히는 버튼이 존재한다.

두 가지 버튼의 차이점은 버튼을 눌렀을 때, UI의 변화 여부이다.

 

위 코드에서

 

1
2
3
useEffect(()=>{
    console.log("useEffect!!", count);
  })
cs

 

와 같이 작성해줬기 때문에 화면이 새로 rendering이 될 때마다 useEffect가 실행되게 된다.

 

이때, count 증가 버튼을 누르게 되면 count가 1 증가하게 되는데(CountUp 함수를 정의해뒀으므로)

count: 1으로 새로 rendering이 되기 때문에 useEffect가 실행된다.

아래 결과를 확인해보자.

 

 

하지만 만약, 클릭 버튼을 누르게 되면 단순히 console에 '클릭'이라는 단어가 찍힐 뿐 화면의 변화는 없으므로 새로 rendering이 되지 않는다. 따라서 useEffect는 실행되지 않고 아래와 같은 결과가 나타난다.

 

 

Theme. 처음 rendering이 됐을 때만 실행

 초기화의 기능을 할 수 있다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function App() {
 
    const [count, setCount] = useState(0);
  
    const CountUp = () => setCount(count + 1); // count++, count+=1 사용 불가능
  
    // useEffect(함수, 배열)
    useEffect(()=>{
      console.log("useEffect!!", count);
    }, [])
  
    return (
      <div>
        <p>count: {count}</p>
        <button onClick={()=>CountUp()}>counter</button>
              </div>
    );
  }
  export default App;
cs

 

위 코드에서 주목할 부분은 아래이다.

 

1
2
3
4
// useEffect(함수, 배열)
    useEffect(()=>{
      console.log("useEffect!!", count);
    }, [])
cs

 

arrow 함수 뒤에 [ ] 이 함께 포함되어 있는데, 이 부분 때문에 처음 rendering 될 때만 useEffect가 실행된다. [ ] 안에 다른 변수가 들어온다면...? 다음 케이스에서 알 수 있다! 

 

위 코드의 결과를 살펴보자.

 

처음 실행됐을 때, useEffect가 실행되는 것을 확인할 수 있다.

 

 

이제 버튼을 눌러 CountUp 함수를 실행시킨 후 결과를 살펴보자.

 

 

count는 증가했지만, useEffect는 실행되지 않음을 확인할 수 있다.

 

 

Theme. 특정 값(변수)이 변경될 때에만 실행되는 예

 

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
function App() {
 
  const [count, setCount] = useState(0);
  const [number, setNubmer] = useState(10);
 
  const CountUp = () => setCount(count + 1); // count++, count+=1 사용 불가능
 
  const NumberDown = () => setNubmer(number - 1);
 
 
  // useEffect(함수, 배열)
  
  useEffect(()=>{
    console.log("useEffect!!", count);
    console.log("useEffect!!", number);
  }, [count]); // count가 변할 때마다 실행 됨(number는 변해도 실행 안됨)
  // [count, number] 였으면 count 또는 number가 변할 때 useEffect 실행됨
  
  return (
    <div>
      <p>count: {count}</p>
      <button onClick={()=>CountUp()}>counter</button>
 
      <p>number: {number}</p>
      <button onClick={()=>NumberDown()}>NumberDown</button>
    </div>
  );
}
 
export default App;
cs

 

위 코드에서 주목해야 할 부분은

 

1
2
3
4
5
6
7
// useEffect(함수, 배열)
  
  useEffect(()=>{
    console.log("useEffect!!", count);
    console.log("useEffect!!", number);
  }, [count]); // count가 변할 때마다 실행 됨(number는 변해도 실행 안됨)
  // [count, number] 였으면 count 또는 number가 변할 때 useEffect 실행됨
cs

 

화면에 count와 number의 값이 나타나므로,

[ ] 안에 들어가는 변수(count 혹은 number)가 변할 때마다 useEffect가 실행된다.

즉, [count] 이면 count가 변할 때마다 useEffect가 실행되고, number가 변하는 것은 영향을 주지 않는다.

만약, [count, number] 였다면 count 또는 number가 변하면 useEffect가 실행된다.

 

처음 실행했을 때는

 

 

 

이를 기준으로 count를 증가시켰을 때,

 

 

처음을 기준으로 number를 감소시켰을 때,

 

 

 

한편, useEffect를 사용하는 다른 코드는 다음과 같다.

이 경우에는 count 또는 number가 변할 때마다 useEffect가 실행되도록 하겠다.

 

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
function App() {
 
  const [count, setCount] = useState(0);
  const [number, setNubmer] = useState(10);
 
  const CountUp = () => setCount(count + 1); // count++, count+=1 사용 불가능
 
  const NumberDown = () => setNubmer(number - 1);
 
  function EffectFunc(){
    console.log("useEffect!!", count);
    console.log("useEffect!!", number);
  }
  
  useEffect(EffectFunc, [count, number]);
 
  return (
    <div>
      <p>count: {count}</p>
      <button onClick={()=>CountUp()}>counter</button>
 
      <p>number: {number}</p>
      <button onClick={()=>NumberDown()}>NumberDown</button>
    </div>
  );
}
 
export default App;
cs

 

끝.

'React' 카테고리의 다른 글

[React] file upload & download  (0) 2023.03.30
[React] axios  (0) 2023.03.29
[React] session과 cookie  (0) 2023.03.29
[React] hook - useState  (0) 2023.03.29
[React] 리액트 시작 및 기초  (0) 2023.03.29

Theme. useState

 

코드와 함께 알아보도록 한다.

useState 사용을 위해서 import 부분에 추가해주는 것을 잊지 말자.

 

아래 코드의 const [ state, setState ] = useState('click'); 에서

state 부분은 getter 부분

setState는 setter 부분

'click'은 초기값

으로 이해하면 된다!

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// import 작성
import React, { useState } from 'react';
 
 
function App() {
  
  // (보호)변수 선언 -> String state = "click"; 과 같은 효과
  //       get      set                 초기값
  const [ state, setState ] = useState('click');
  
  console.log(state); 
  // state = 'abc'; 에러! - 상수에 대입은 불가능
  // setState('abc'); 에러! - 다시 초기화 할 수 없음
 
  return (
    <div>
      <button onClick={() => setState('clicked')}>{state}</button>
    </div>
  );
}
 
export default App;
cs

 

그 결과 버튼을 누르기 전과 후를 비교하면,

 

 

 

 

간단한 예시들을 추가로 살펴보자.

 

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
32
33
34
35
36
const INITIAL_COUNT = 0// 상수
 
function App(){
 
  const [message, setMessage] = useState("");
  const [number, setNumber] = useState(INITIAL_COUNT);
  // const [number, setNumber] = useState(0);
 
  const btnclick = () => {  
    alert(message);
  }
 
  function counterBtn(){
    setNumber(number + 1);
  }
 
  const initCount = () => {
    setNumber(INITIAL_COUNT);
  }
 
  return (
    <div>
      <input onChange={(e) => {setMessage(e.target.value)}} />
 
      <button onClick={btnclick}>message보기</button>
      <button onClick={() => btnclick()}>message보기</button>
 
      <p>{number}</p>
      <button onClick={counterBtn}>카운터</button>
      <button onClick={initCount}>초기화</button>
 
    </div>
  )
}
 
export default App;
cs

 

우선, {btnclick}과 { () => btnclick() }이 같은 효과를 나타내는 것을 확인하기 위해 함께 적어두었다.

 

버튼을 클릭하지 않고, 초기 결과를 살펴보면 아래와 같다.

 

 

onChange 이벤트를 통해 input에 값을 입력하게 되면, 이를 message보기라는 버튼을 통해 확인할 수 있다.(alert)

 

또한, 카운터라는 버튼을 누르면 counterBtn()이 실행되고, setNumber(number + 1);에 의해 초기값 0에서 number가 1 증가하게 된다. (이때 주의할 것은 number++, number+=1과 같이 작성할 수 없다는 것이다) 

 

< input 태그에서의 useState 사용 >

 

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
function App(){
 
  const [inputTextVal, setInputTextVal] = useState("초기값");
  const [text, setText] = useState("React");
 
  const handleChange = (e) => setInputTextVal(e.target.value);
  
  // const handleChange = (e) => {
  //   setInputTextVal(e.target.value);
  // }
 
  const handleClick = () => {
    setText(inputTextVal);
    setInputTextVal("초기값");
  }
 
  return (
    <div>
      <h1>I love {text}</h1>
 
      <input type="text" value={inputTextVal} onChange={handleChange} />
 
      <input type="button" value="입력" onClick={() => handleClick()} />
    </div>
    
  )
 
}
 
export default App;
cs

 

초기 결과는,

 

 

이때, input 태그에 값을 입력하게 되면, onChange 이벤트에 의해 handleChange 함수가 실행된다.

그리고 입력한 값이 handleChange 함수에서 setInputTextVal에 의해 inputTextVal을 변하게 한다.

즉, input의 value값이 입력한 값으로 나타나는 것이다.

이때, '입력'버튼을 누르게 되면(onClick) handleClick 함수가 실행되고, setText를 통해 text의 값을 변하게 한다.

 

그래서 만약 input 태그에 'you'라고 입력하고 입력 버튼을 누르게 되면,

 

 

 

< select 태그에서의 useState 사용 >

 

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
32
33
34
35
36
37
38
39
40
// select
const SelectBox = () => { // Component명의 첫 글자는 대문자 
  const [selectedVal, setSelectedVal] = useState("HTML");
 
  const handleChange = (e) => {
    setSelectedVal(e.target.value);
  }
 
  const SelectChoice = () => {
    alert(selectedVal);
  }
 
 
  return(
    <div>
      <p>현재 선택된 항목: <strong>{selectedVal}</strong></p>
 
      <select value={selectedVal} onChange={handleChange}>
        <option value="HTML">HTML</option>
        <option value="CSS">CSS</option>
        <option value="REACT">REACT</option>
      </select>
 
      <button onClick={() => SelectChoice()}>선택된 값</button>
 
    </div>
  )
 
}
 
function App(){
 
  return(
    <div>
      <SelectBox />
    </div>
  )
}
 
export default App;
cs

 

 

만약, CSS를 선택하고, onClick을 통해 선택된 값을 확인해보면,

 

 

 

< radio에서의 useState 사용 >

 

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
// radio
function InputRadio(){
  const [radioVal, setRadioVal] = useState("red");
 
  function handleChange(e){
    setRadioVal(e.target.value);
  }
 
  return(
    <div>
      <p>선택된 항목: <strong>{radioVal}</strong></p>
      <input type="radio" value="red" onChange={handleChange} checked={radioVal === "red"/>빨강
      <input type="radio" value="green" onChange={handleChange} checked={radioVal === "green"/>초록
      <input type="radio" value="blue" onChange={handleChange} checked={radioVal === "blue"/>파랑
 
    </div>
  )
}
 
function App(){
  return(
    <div>
      <InputRadio></InputRadio>
    </div>
  )
}
 
export default App;
 
cs

 

이때, "=="는 주소의 비교이고, "==="는 값의 비교이다.

 

초기 결과와 파랑을 선택했을 때의 결과는

 

 

 

<  checkbox에서의 useState 사용 >

 

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
// checkbox
 
const InputCheckBox = () => {
  const [ checkedVal, setCheckedVal] = useState(false); // 체크 안됨
 
  const handleChange = (e) => {
    setCheckedVal(!checkedVal); // 체크가 되거나 안되거나 반대로!
  }
 
  return(
    <div>
      <input type="checkbox" onChange={handleChange} checked={checkedVal} />독서
    </div>
  )
 
}
 
function App(){
  return(
    <div>
      <InputCheckBox/>
    </div>
  )
}
 
export default App;
cs

 

< random 넘버 생성 및 현재 날짜 나타나도록 하기 >

 

참고로,

const [ randState, setRandState ] = useState(0); 부분은

var randNumberState = useState(0); // 배열! 0은 초기값

var randState = randNumberState[0];

var setRandState = randNumberState[1];

로 바꿀 수 있다. 

 

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
32
33
34
35
36
37
//random
function RandAndDate(){
  // const [randState, setRandState] = useState(0);
  var randNumberState = useState(2); // 배열
  var randState = randNumberState[0];
  var setRandState = randNumberState[1];
 
  const [mydate, setMydate] = useState("");
 
  const nowDate = () => {
    setMydate( (new Date()).toString() ); // 현재 날짜
  }
 
 
  return(
    <div>
      <p>Number:{randState}</p>
      <p>Date:{mydate}</p> 
      <input type="button" value="random" 
        onClick=function() {
                      setRandState(parseInt(Math.random()*10))
                    }} />
      <input type="button" value="Date" onClick={nowDate} />              
    </div>
  );
}
 
function App(){
  return(
    <div>
      <RandAndDate/>
    </div>
  )
}
 
 
export default App;
cs

 

 

 

 

 

끝.

'React' 카테고리의 다른 글

[React] file upload & download  (0) 2023.03.30
[React] axios  (0) 2023.03.29
[React] session과 cookie  (0) 2023.03.29
[React] hook - useEffect  (0) 2023.03.29
[React] 리액트 시작 및 기초  (0) 2023.03.29

Theme. 리액트의 시작

 - node.js를 설치했고, vs code를 사용한다.

 

< "터미널"에서 사용되는 명령어! >

1. 프로젝트 생성

npx create-react-app 프로젝트명

 

2. 프로젝트 실행

cd 프로젝트 명

npm start

 

3. 서버 끄기(작업끝내기)

ctrl + c

 

4. 상위 폴더로 이동

cd .. 

 

Theme. 컴포넌트(Component) 만들기

 Component는 사용자 정의  태그이다. 리액트에서의 속성은 prop이라고 한다.

 

 간단하게 Component를 만들고, 동시에 props를 사용해보자.

 

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
function App() {
 
  function Message(){ // component 만드려는 함수의 첫글자는 대문자!
    return <h1>Hello React</h1>
  }
 
  function MessageOne(props){ // props는 가인수
    return ( // 여러 태그를 return 해줄 때는 div태그로 묶어서 작성해야 한다
      <div>
        <h2>Hello {props.name}</h2>
        <p>Hi {props.name}</p>
      </div>
    )
  }
 
  return (
    <div>
      {Message()} {/* 함수 호출 */}
      
      <Message></Message>     {/* component */}
      <Message />             {/* component */}
 
      <MessageOne name="춘향" /> {/* component */}
    </div>
  );
}
 
export default App;
cs

 

실행 결과는 아래와 같다.

 

 

먼저, <Message>, <MessageOne>이라는 태그를 만들기 위해서, 즉 컴포넌트를 만들기 위해서 function 방식을 이용했다. 이때 함수명의 첫글자는 반드시 대문자여야 한다.

<MessageOne name="춘향"> 에서 MessageOne이라는 function이 props을 통해 name="춘향"이라는 object를 받게 된다. 그래서 {props.name}와 같이 사용이 가능하다. key값이 name, 그 value는 "춘향"인 셈.

 

추가적으로, message.js라는 파일을 만들고, 그 안에 MessageTwo라는 function을 만들어 컴포넌트를 만드려고 한다.

외부에서 만들어준 것이기 때문에

import MessageTwo from './message'; 를 작성해줘야 한다. (동일 프로젝트 내에 존재하므로 ./ 이다)

 

먼저, message.js은 다음과 같다.

 

1
2
3
4
5
6
7
8
 
function MessageTwo(props){
  console.log('MessageTwo 호출');
 
  return <div>nice to meet you {props.name</div>
}
 
export default MessageTwo;
cs

 

코드가 추가된 App.js은 다음과 같다. 

 

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
32
33
34
35
36
37
import MessageTwo from './message';
 
function App() {
 
  function Message(){ // component 만드려는 함수의 첫글자는 대문자!
    return <h1>Hello React</h1>
  }
 
  // function MessageOne(props){ // props는 가인수
  //   return <h2>Hello {props.name}</h2>
  // }
 
  function MessageOne(props){ // props는 가인수
    return ( // 여러 태그를 return 해줄 때는 div태그로 묶어서 작성해야 한다
      <div>
        <h2>Hello {props.name}</h2>
        <p>Hi {props.name}</p>
      </div>
    )
  }
 
  return (
    <div>
      {Message()}
 
      <Message></Message>     {/* component */}
      <Message />             {/* component */}
 
      <MessageOne name="춘향" /> {/* component */}
 
      <MessageTwo name="홍두깨" /> {/* component */}
    </div>
  );
}
 
export default App;
 
cs

 

 

그 결과는,

 

 

 

 

Theme. map의 사용

 

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
function App(){
 
  // return (
  //   <div>
  //     <ul>
  //       <li>Apple</li>
  //       <li>Banana</li>
  //       <li>Pear</li>
  //     </ul>
  //   </div>
  // )
 
  // 위와 같은 효과를 나타내기 위해서 map을 사용한다면?
  
  const arr = ["apple""pear""banana"];
// map 사용시 key값을 넣어줘야 하는 규칙에 주의
  const datalist = arr.map((a, index) => (<li key={index}>{index} {a}</li>))
 
  return(
    <div>
      {datalist}
    </div>
  )
 
}
 
export default App;
cs

 

 

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
function App(){
 
  const members = [
    { "number":1"name":"홍길동""height":172.1 },
    { "number":2"name":"성춘향""height":158.1 },
    { "number":3"name":"일지매""height":181.1 }
  ];
  // map 사용시 key값을 넣어줘야 하는 규칙에 주의
  const memberlist = members.map(function(member, index){
 
    return (
      <tr key={index}>
        <th>{member.number}</th>
        <td>{member.name}</td>
        <td>{member.height}</td>
      </tr>
    )
  });
 
  return (
    <div>
      <table border="1">
        <tbody>
          {memberlist}
        </tbody>
      </table>
    </div>
  )
}
 
export default App;
cs

 

위와 같은 결과를 나타내는 코드를 다시 작성해보자.

 

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
32
function App(){
 
  const members = [
    { "number":1"name":"홍길동""height":172.1 },
    { "number":2"name":"성춘향""height":158.1 },
    { "number":3"name":"일지매""height":181.1 }
  ];
 
  const memfunc = (member, index) => {
    return (
      <tr key={index}>
        <th>{member.number}</th>
        <td>{member.name}</td>
        <td>{member.height}</td>
      </tr>
    )
  }
 
  const memberlist = members.map(memfunc);
 
  return (
    <div>
      <table border="1">
        <tbody>
          {memberlist}
        </tbody>
      </table>
    </div>
  )
}
 
export default App;
cs

 

 

 

 

그 결과는,

 

 

 

Theme. 이벤트

 

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
function App(){
  
  function btnclick(){
    alert('btnclick');
  }
 
  function inputFunc(e){
    console.log(e.target.value)
  }
 
  return (
    <div>
      <button onClick={ () => btnclick() }>버튼</button>
 
      <button onClick={ () => {console.log('버튼클릭')} }>버튼</button>
 
      <input type="text" onChange={ (event=> {console.log(event.target.value)}} />
     
      <input type="text" onChange={ inputFunc } />
 
      <input type="checkbox" />
    </div>
  )
}
export default App;
cs

 

먼저, (event) => ..... 에서의 event와 inputFunc(e)에서의 e 모두 이벤트 객체이다.

이벤트 객체는 이벤트 상황을 제어할 수 있는 여러가지 정보와 기능이 있다.

이중, 위에서 event.target.value 부분의 의미를 살펴보면,

event.target은 이벤트를 발생시킨 target! 이벤트를 발생시킨 부분! 을 말하는 것이고,

event.target.value는 이벤트를 발생시킨 target의 value를 가져온다는 의미이다.

이때, input 태그를 사용했기 때문에 value를 적은 것이다.

onChange 이벤트이므로 input 부분에 텍스트를 적거나 고칠 때마다 console에 나타내게 된다.

 

 

 

 

 

 

 

'React' 카테고리의 다른 글

[React] file upload & download  (0) 2023.03.30
[React] axios  (0) 2023.03.29
[React] session과 cookie  (0) 2023.03.29
[React] hook - useEffect  (0) 2023.03.29
[React] hook - useState  (0) 2023.03.29

https://www.acmicpc.net/problem/2744

 

2744번: 대소문자 바꾸기

영어 소문자와 대문자로 이루어진 단어를 입력받은 뒤, 대문자는 소문자로, 소문자는 대문자로 바꾸어 출력하는 프로그램을 작성하시오.

www.acmicpc.net

 

문제를 풀기에 앞서 ASCII Code에 대해서 필요한 정보를 정리하고 넘어가자.

간단하게 char에 해당되는 정수 값이 존재한다고 생각하면 된다.

예를 들어, 문자 A의 ASCII Code 값은 65이다.

아래 테이블을 참고하자.

 

 

중요한건, 문제를 풀 때, 각 문자에 해당되는  ASCII Code 값을 알아야하는 게 아니라는 것이다.

어떻게 활용하면 되는가?

 

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
package String;
 
public class StringClass {
    
    public static void main(String[] args) {
        
        // ASCII Code값을 char 변수에 넣으면, 그 변수에 ASCII Code값에 해당하는 문자가 저장된다.
        char x = 65;
        System.out.println(x); // A
        
        // 문자끼리 연산이 가능 -> 문자 사이의 간격만큼 결과가 나타남
        int n = 'Z' - 'A';
        System.out.println(n); // 25 -- A는 1번째, Z는 26번째 문자니까
        
        // char와 int 사이에 연산이 가능
        System.out.println(x + 25); // 90
        
        // 문자끼리 대소비교가 가능(ASCII Code 값으로 대소비교)
        System.out.println('A' < 'Z'); // true
        
        // Casting
        // char를 int로 형변환 가능(ASCII Code 값 저장)
        System.out.println((int)x); // 65
        
        // int를 char로 형변환 가능(ASCII Code 값이 해당 int 값인 char이 반환)
        System.out.println((char)(x + 25)); // Z (ASCII Code값이 90)
    }
}
 
cs

 

이를 활용하여 간단하게 대소문자를 변환해보자.

중요한 생각은 A와 Z 사이의 간격은 a와 z 사이의 간격과 같다는 것!

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package String;
 
public class StringClass {
    
    public static void main(String[] args) {
        
        String str = "AbCdEf";
        for (int i = 0; i < str.length(); i++) {
            // 대문자의 경우!
            if('A' <= str.charAt(i) && str.charAt(i) <= 'Z') {
//                int dist = str.charAt(i) - 'A';    // A와의 간격
                System.out.print((char)('a' + str.charAt(i) - 'A')); // a로부터 해당 간격만큼 떨어진 문자로!
            } 
            else {
                System.out.print((char)('A' + str.charAt(i) - 'a'));
            }
        }
    }
}
 
cs

 

AbCdEf가 aBcDeF로 변환됨을 알 수 있다.

 

이제 [BOJ] 2744. 대소문자 바꾸기 문제를 풀어보자.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import java.util.Scanner;
 
public class Main {
 
    public static void main(String[] args) {
 
        Scanner sc = new Scanner(System.in);
        String str = sc.next();
        String answer = "";
        for (int i = 0; i < str.length(); i++) {
            if ('A' <= str.charAt(i) && str.charAt(i) <= 'Z') { // 대문자라면,
                answer += (char)('a' + str.charAt(i) - 'A');
            } else { // 소문자라면,
                answer += (char)('A' + str.charAt(i) - 'a');
            }
        }
        System.out.println(answer);
    }
 
}
cs

 

 

또는,

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import java.util.Scanner;
 
public class Main {
 
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        String str = sc.next();
        char[] arr = str.toCharArray();
        for (int i = 0; i < str.length(); i++) {
            char ch = str.charAt(i);
            if('A' <= ch && ch <= 'Z') {
                arr[i] = (char)('a' + ch - 'A');
            } else {
                arr[i] = (char)('A' + ch - 'a');
            }
            
        }
        
        System.out.println(arr);
    }
 
}
 
cs

 

끝.

 

'알고리즘 및 코테 > 자료구조 및 알고리즘' 카테고리의 다른 글

[String] 문자열(Java)  (0) 2023.03.22

Theme. Spring Boot를 DB와 연결하기 위한 설정

 

< pom.xml >

 

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.0.5</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>sample3-db</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>sample3-db</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>17</java.version>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
 
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-tomcat</artifactId>
        </dependency>
        
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-core</artifactId>
            <version>2.14.1</version>
        </dependency>
        
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.14.1</version>
        </dependency>
        
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId> <!-- Spring Boot 버전과 동일하게 맞춰줄 것 -->
        </dependency>
        
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>3.0.1</version>
        </dependency>
        
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>3.0.1</version>
        </dependency>
        
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.11</version>
        </dependency>
        
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.29</version>
        </dependency>
        
    </dependencies>
 
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
 
</project>
 
cs

 

 

< application.properties >

 

1
2
3
4
5
6
7
8
 
server.port=3000
 
spring.datasource.hikari.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.hikari.jdbc-url=jdbc:mysql://localhost:포트넘버/DB명?serverTimeZone=Asia/Seoul
spring.datasource.hikari.username=아이디
spring.datasource.hikari.password=비밀번호
 
cs

 

< DB Config >

 

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
package mul.cam.a;
 
import javax.sql.DataSource;
 
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
 
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
 
@Configuration
@PropertySource("classpath:/application.properties")
public class DatabaseConfig {
    
    @Bean
    @ConfigurationProperties(prefix = "spring.datasource.hikari")
    public HikariConfig hikariConfig() {
        return new HikariConfig();
    }
    
    @Bean
    public DataSource dataSource() {
        DataSource dataSource = new HikariDataSource(hikariConfig());
        System.out.println("dataSource: " + dataSource);
        
        return dataSource;
    }
    
    @Bean
    public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
        System.out.println("DatabaseConfig sqlSessionFactory");
        
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(dataSource);
        
        Resource[] arrResource = new PathMatchingResourcePatternResolver().getResources("classpath:sqls/*.xml");
        sqlSessionFactoryBean.setMapperLocations(arrResource);
        sqlSessionFactoryBean.getObject().getConfiguration().setMapUnderscoreToCamelCase(true);
        
        return (SqlSessionFactory)sqlSessionFactoryBean.getObject();
    }
    
    @Bean
    public SqlSessionTemplate sqlSession(SqlSessionFactory sqlSessionFactory) {
        return new SqlSessionTemplate(sqlSessionFactory);
    }
    
    
}
 
cs

 

 

간단한 예시로 Member.xml - MemberDao - MemberService - MemberController 순으로 연결을 간단하게 살펴보자.

사용되는 MemberDto는 아래와 같다.

 

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
package mul.cam.a.dto;
 
public class MemberDto {
    
    private String id;
    private String pwd;
    private String name;
    private String email;
    private int auth;
    
    public MemberDto() {
    }
 
    public MemberDto(String id, String pwd, String name, String email, int auth) {
        super();
        this.id = id;
        this.pwd = pwd;
        this.name = name;
        this.email = email;
        this.auth = auth;
    }
 
    public String getId() {
        return id;
    }
 
    public void setId(String id) {
        this.id = id;
    }
 
    public String getPwd() {
        return pwd;
    }
 
    public void setPwd(String pwd) {
        this.pwd = pwd;
    }
 
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
    public String getEmail() {
        return email;
    }
 
    public void setEmail(String email) {
        this.email = email;
    }
 
    public int getAuth() {
        return auth;
    }
 
    public void setAuth(int auth) {
        this.auth = auth;
    }
 
    @Override
    public String toString() {
        return "MemberDto [id=" + id + ", pwd=" + pwd + ", name=" + name + ", email=" + email + ", auth=" + auth + "]";
    }
    
 
}
 
cs

 

 

< Member.xml >

주의할 것은 mapper의 namespace에 패키지명도 함께 적어야한다는 것이고, sql문 부분의 id값이 dao에서의 함수명으로 동일하게 사용된다는 것이다. 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
    "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    
<mapper namespace="mul.cam.a.dao.MemberDao"> <!-- mapper에 패키지명도 적어야! -->
 
<select id="allMember" resultType="mul.cam.a.dto.MemberDto">
    select id, pwd, name, email, auth
    from member
</select>
 
</mapper>
 
 
 
 
cs

 

 

< MemberDao.java >

MemberDao.java는 인터페이스이다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package mul.cam.a.dao;
 
import java.util.List;
 
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;
 
import mul.cam.a.dto.MemberDto;
 
@Mapper    // Member.xml의 id값이 그대로 함수명이 된다.
@Repository
public interface MemberDao {
    
    // 함수명은 반드시 Member.xml의 해당 id값과 동일해야 한다
    List<MemberDto> allMember();
    
}
 
cs

 

 

< MemberService.java >

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package mul.cam.a.service;
 
import java.util.List;
 
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
 
import mul.cam.a.dao.MemberDao;
import mul.cam.a.dto.MemberDto;
 
@Service
@Transactional
public class MemberService {
 
    @Autowired
    MemberDao dao;
    
    public List<MemberDto> allMember(){ // dao와 함수명이 꼭 같을 필요는 없다.
        return dao.allMember();
    }
}
 
cs

 

< MemberController.java >

 

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
package mul.cam.a.controller;
 
import java.util.Date;
import java.util.List;
 
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
 
import mul.cam.a.dto.MemberDto;
import mul.cam.a.service.MemberService;
 
@RestController
public class MemberController {
    
    @Autowired
    MemberService service;
    
    @GetMapping(value = "/allList")
    public List<MemberDto> allList(){
        System.out.println("MemberController allList " + new Date());
        
        return service.allMember();
    }
}
 
cs

 

 

끝.

 

 

'Spring' 카테고리의 다른 글

[Spring Boot] File 업로드 및 다운로드  (0) 2023.03.26
[Spring Boot] 스프링 부트 실행 및 기초  (0) 2023.03.26

Theme. 파일 업로드 및 다운로드

 

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
package mul.cam.a.controller;
 
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.Date;
 
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.InputStreamResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
 
import jakarta.servlet.ServletContext;
import jakarta.servlet.http.HttpServletRequest;
import mul.cam.a.MediaTypeUtiles;
import mul.cam.a.dto.HumanDto;
 
@RestController
public class HelloController {
 
    // file upload
    @RequestMapping(value = "/fileUpload", method = RequestMethod.POST)
    public String fileUpload(HumanDto human,
                             @RequestParam("uploadFile")
                             MultipartFile uploadFile,
                             HttpServletRequest req) {
        
        System.out.println("HelloController fileUpload " + new Date());
        System.out.println(human.toString());
        
        // 경로
        String path = req.getServletContext().getRealPath("/upload"); // 서버에 업로드
//        String path = "c:\temp"; // 폴더에 upload
        
        
        String filename = uploadFile.getOriginalFilename(); // 기본 파일명
        String filepath = path + "/" + filename;
        
        System.out.println(filepath);
        
        File file = new File(filepath);
        try {
            BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file));
            bos.write(uploadFile.getBytes());
            bos.close();
        
        } catch (Exception e) {
            return "file upload fail";
        } 
        return "file upload success";
        
    }
    
    // file download
    @Autowired
    ServletContext servletContext;
    
    @RequestMapping(value = "/fileDownload")
    public ResponseEntity<InputStreamResource> download(String filename, HttpServletRequest req) throws Exception{
        System.out.println("HelloController download " + new Date());
        
        // 경로
        String path = req.getServletContext().getRealPath("/upload");
        
        MediaType mediaType = MediaTypeUtiles.getMediaTypeForFileName(this.servletContext, filename);
        System.out.println("filename: " + filename);
        System.out.println("mediaType: " + mediaType);
        
        File file = new File(path + "/" + filename); // filename은 업로드됐을 때의 new filename
//        File file = new File(path + File.separator + filename);
        
        InputStreamResource isr = new InputStreamResource(new FileInputStream(file));
        
        // db에서 다운로드 카운트 넣으려면 이 곳에 넣음
        
        return ResponseEntity.ok()
                .header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + file.getName()) // file.getName()은 원본 파일명
                .contentType(mediaType)
                .contentLength(file.length())
                .body(isr);
    }
    
    
    
    
}
 
cs

 

이때 사용된 static 메서드는 아래 클래스에 나타내었다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package mul.cam.a;
 
import org.springframework.http.MediaType;
 
import jakarta.servlet.ServletContext;
 
public class MediaTypeUtiles {
 
    public static MediaType getMediaTypeForFileName(ServletContext servletContext, String filename) {
        
        String minType = servletContext.getMimeType(filename);
        
        try {
            MediaType mediaType = MediaType.parseMediaType(minType);
            return mediaType;
        } catch (Exception e) {
            return MediaType.APPLICATION_OCTET_STREAM;
        }
        
        
    }
}
 
cs

 

이때, 주의할 것은 프로젝트에 upload 폴더를 추가해줘야 한다는 것이다.

아래와 같이 main 폴더 하위에 webapp 폴더를 생성하고, 그 안에 upload 폴더를 생성해주도록 하자.

 

 

또한, HumanDto 클래스의 경우에는 다음과 같다.

 

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
package mul.cam.a.dto;
 
public class HumanDto {
    
    private int number;
    private String name;
    private String address;
    
    public HumanDto() {}
 
    public HumanDto(int number, String name, String address) {
        super();
        this.number = number;
        this.name = name;
        this.address = address;
    }
 
    public int getNumber() {
        return number;
    }
 
    public void setNumber(int number) {
        this.number = number;
    }
 
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
    public String getAddress() {
        return address;
    }
 
    public void setAddress(String address) {
        this.address = address;
    }
 
    @Override
    public String toString() {
        return "HumanDto [number=" + number + ", name=" + name + ", address=" + address + "]";
    }
    
    
}
 
cs

 

이제 html 파일을 만들어서 파일 업로드 및 다운로드를 실행해보자. 

abc.txt라는 파일을 업로드 및 다운로드한다. 

 

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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.3/jquery.min.js"></script>
</head>
<body>
 
<h3>file upload</h3>
 
<p id="fileResult">...</p>
 
<form id="uploadFileForm">
    number:<input type="text" name="number" value="1002"><br>
    name:<input type="text" name="name" value="성춘향"><br>
    address:<input type="text" name="address" value="남원시"><br><br>    
    
    file:<input type="file" name="uploadFile"><br><br> <!-- controller에서 requestparam 부분 uploadFile과 이름 맞췄다. -->
    
    <button type="button" id="uploadBtn">파일업로드</button>    
</form>
 
<script type="text/javascript">
$(document).ready(function(){
    $("#uploadBtn").click(function(){
        
        $.ajax({
            url:"http://localhost:3000/fileUpload",
            type:"post",
            data:new FormData($("#uploadFileForm")[0]),
            enctype:'multipart/form-data',
            processData:false,
            contentType:false,
            cache:false,
            success:function(str){
                alert('success');
                $("#fileResult").text(str);
            },
            error:function(){
                alert('error');
            }
        });        
    });
});
</script>
 
<br><br>
 
<h3>file download</h3>
 
<button type="button" id="downloadBtn">파일 다운로드</button>
 
<script type="text/javascript">
 
$("#downloadBtn").click(function(){
    
    location.href = "http://localhost:3000/fileDownload?filename=" + "abc.txt";
    
    /* 
    아래 코드는 success는 나오지만, 다운로드는 실행되지 않을 것이다.
    즉, 아래와 같이 다운로드 하면 안된다. 
    
    $.ajax({
        url:"http://localhost:3000/fileDownload",
        type:"get",
        data:{ filename:"abc.txt" },
        success:function(){
            alert('success');    
        },
        error:function(){
            alert('error');
        }        
    });
    */
});
 
</script>
 
</body>
</html>
 
 
 
 
 
 
 
 
 
 
cs

 

 

실행 결과는,

 

 

 

 

 

 

 

 

끝.

 

 

'Spring' 카테고리의 다른 글

[Spring Boot] DB와 연결하기  (0) 2023.03.26
[Spring Boot] 스프링 부트 실행 및 기초  (0) 2023.03.26

+ Recent posts