<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>파이팅웨이</title>
    <link>https://fightingway.tistory.com/</link>
    <description>https://github.com/saaut</description>
    <language>ko</language>
    <pubDate>Fri, 26 Jun 2026 22:27:25 +0900</pubDate>
    <generator>TISTORY</generator>
    <ttl>100</ttl>
    <managingEditor>코오오 코오</managingEditor>
    <image>
      <title>파이팅웨이</title>
      <url>https://tistory1.daumcdn.net/tistory/5396614/attach/0959a1864ffb464eaaf43b367c71d9e9</url>
      <link>https://fightingway.tistory.com</link>
    </image>
    <item>
      <title>SpringBoot 게시판 만들기-2. 댓글 기능 구현</title>
      <link>https://fightingway.tistory.com/45</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;글 조회.png&quot; data-origin-width=&quot;1160&quot; data-origin-height=&quot;857&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/donmuR/btsFoEKVkDn/lrU6Wf4hOCVOWNUDch1K4K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/donmuR/btsFoEKVkDn/lrU6Wf4hOCVOWNUDch1K4K/img.png&quot; data-alt=&quot;미리 만들어둔 뷰&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/donmuR/btsFoEKVkDn/lrU6Wf4hOCVOWNUDch1K4K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdonmuR%2FbtsFoEKVkDn%2FlrU6Wf4hOCVOWNUDch1K4K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;739&quot; height=&quot;546&quot; data-filename=&quot;글 조회.png&quot; data-origin-width=&quot;1160&quot; data-origin-height=&quot;857&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;미리 만들어둔 뷰&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;b&gt;댓글 기능을 하려면?&lt;/b&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1. 도메인 작성&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2. 리포지토리 작성&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. 서비스 메서드 작성&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4. 컨트롤러 작성&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5. 뷰 작성&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;1. 도메인 작성&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;댓글 기능에 필요한 건?&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1-1. 댓글 id&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1-2. 댓글 내용&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1-3. 댓글 생성 시간&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1-4. 댓글 수정 시간&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1-5. 댓글 작성자&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1-6. 댓글이 달린 게시글 표시(댓글과 게시글은 다대일 관계이다.)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위 내용을 바탕으로 comment 엔티티를 설계해준다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;comment.png&quot; data-origin-width=&quot;900&quot; data-origin-height=&quot;333&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bQy43c/btsFywc4xco/kMUbNf57fr6hAlHYiDQGQ1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bQy43c/btsFywc4xco/kMUbNf57fr6hAlHYiDQGQ1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bQy43c/btsFywc4xco/kMUbNf57fr6hAlHYiDQGQ1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbQy43c%2FbtsFywc4xco%2FkMUbNf57fr6hAlHYiDQGQ1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;744&quot; height=&quot;275&quot; data-filename=&quot;comment.png&quot; data-origin-width=&quot;900&quot; data-origin-height=&quot;333&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;comment.java&lt;/p&gt;
&lt;pre id=&quot;code_1709654194593&quot; class=&quot;kotlin&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;@Builder
@AllArgsConstructor
@NoArgsConstructor
@Getter
@Table(name = &quot;comments&quot;)
@Entity
public class Comment {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(columnDefinition = &quot;TEXT&quot;, nullable = false)
    private String comment;

    @Column(name = &quot;created_date&quot;)
    @CreatedDate
    private LocalDateTime createdDate;

    @Column(name = &quot;modified_date&quot;)
    @LastModifiedDate
    private LocalDateTime modifiedDate;

    @ManyToOne
    @JoinColumn(name = &quot;article_id&quot;)
    private Article article;

    @ManyToOne
    @JoinColumn(name = &quot;user_id&quot;)
    private User user; // 작성자

    //댓글 수정
    public void update(String comment) {
        this.comment = comment;
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미 작성해 둔 Article 엔티티에도, 댓글을 추가해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Article.java&lt;/p&gt;
&lt;pre id=&quot;code_1709654194594&quot; class=&quot;kotlin&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;@Entity
@Getter//모든필드에 대한 접근자 메서드 생성
@NoArgsConstructor(access = AccessLevel.PROTECTED)//기본 생성자 생성
public class Article {
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name=&quot;id&quot;,updatable = false)
    private Long id;

    @Column(name=&quot;title&quot;,nullable = false)
    private String title;

    @Column(name=&quot;content&quot;,nullable = false)
    private String content;
    @Column(name=&quot;author&quot;,nullable = false)
    private String author;


    @Builder
    public Article(String author,String title,String content,String comment){
        this.author=author;
        this.title=title;
        this.content=content;
    }
    public void update(String title,String content){
        this.title=title;
        this.content=content;
    }
    @CreatedDate//엔티티가 생성될 때 생성 시간 저장
    @Column(name=&quot;created_at&quot;)
    private LocalDateTime createdAt;

    @LastModifiedDate//엔티티가 수정될 때 수정 시간 저장
    @Column(name=&quot;updated_at&quot;)
    private LocalDateTime updatedAt;

    @OneToMany(mappedBy = &quot;article&quot;, fetch = FetchType.EAGER, cascade = CascadeType.REMOVE)
    @OrderBy(&quot;id asc&quot;) // 댓글 정렬
    private List&amp;lt;Comment&amp;gt; comments;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;@OneToMany 애너테이션은 일대다 관계를 나타낸다. 게시글 하나에 여러 댓글이 달릴 수 있음.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;mappedBy 속성을 통해 article 필드가 관계의 주인으로 매핑됨을 나타낸다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;FetchType.EAGER&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;는 연관된 엔티티를 즉시 로딩하는 전략.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CascadeType.REMOVE&lt;span style=&quot;background-color: #ffffff; color: #0d0d0d; text-align: start;&quot;&gt;가 지정되어 있어, 부모 엔티티가 삭제될 때 관련된 모든 자식 엔티티도 함께 삭제된다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;2. 리포지토리 작성&lt;/b&gt;&lt;/h4&gt;
&lt;pre id=&quot;code_1709654194595&quot; class=&quot;routeros&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;public interface CommentRepository extends JpaRepository&amp;lt;Comment,Long&amp;gt; {
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;여기까지가 엔티티를 구성하는 과정.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;다음으로는 API 를 구현한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;3. 서비스 메서드 작성&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3-1. dto 작성&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;서비스 계층에서 요청을 받을 객체 생성&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;AddCommentRequest.java&lt;/p&gt;
&lt;pre id=&quot;code_1709654194595&quot; class=&quot;reasonml&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;@NoArgsConstructor
@AllArgsConstructor
@Getter
public class AddCommentRequest {
    private Long id;
    private String comment;
    private String createdDate = LocalDateTime.now().format(DateTimeFormatter.ofPattern(&quot;yyyy.MM.dd HH:mm&quot;));
    private String modifiedDate = LocalDateTime.now().format(DateTimeFormatter.ofPattern(&quot;yyyy.MM.dd HH:mm&quot;));
    private String user;
    private int article;

    public Comment toEntity() {//생성자를 사용해 객체 생성
        return Comment.builder()
                .comment(comment)
                .createdDate(createdDate)
                .modifiedDate(modifiedDate)
                .user(user)
                .article(article)
                .build();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3-2. 서비스 메서드 작성&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CommentService.java&lt;/p&gt;
&lt;pre id=&quot;code_1709654194595&quot; class=&quot;reasonml&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;@RequiredArgsConstructor
@Service
public class CommentService {

    private final CommentRepository commentRepository;
    private final UserRepository userRepository;
    private final BlogRepository blogRepository;

    //댓글 추가 메서드
    public Comment save(Long id,AddCommentRequest request, String userName) {
        Optional&amp;lt;User&amp;gt; userOptional = userRepository.findByEmail(userName);
        User user;
        if (userOptional.isPresent()) { // Optional이 값으로 채워져 있는지 확인
            user = userOptional.get(); // User 객체 추출
        } else {
            System.out.println(&quot;사용자가 존재하지 않습니다: &quot; + userName);
            return null;
        }
        Article article = blogRepository.findById(id).orElseThrow(() -&amp;gt;
                new IllegalArgumentException(&quot;댓글 쓰기 실패: 해당 게시글이 존재하지 않습니다. &quot; + id));

        request.setUser(user);
        request.setArticle(article);

        return commentRepository.save(request.toEntity());
    }
    //댓글을 읽어온다.
    @Transactional(readOnly = true)
    public List&amp;lt;Comment&amp;gt; findAll(Long id) {
        Article article = blogRepository.findById(id).orElseThrow(() -&amp;gt;
                new IllegalArgumentException(&quot;해당 게시글이 존재하지 않습니다. id: &quot; + id));
        List&amp;lt;Comment&amp;gt; comments = article.getComments();
        return comments;
    }

    //댓글 업데이트
    @Transactional
    public void update(Long articleId, Long id, UpdateCommentRequest dto) {
        Comment comment = commentRepository.findByArticleIdAndId(articleId, id).orElseThrow(() -&amp;gt;
                new IllegalArgumentException(&quot;해당 댓글이 존재하지 않습니다. &quot; + id));

        comment.update(dto.getComment());
    }

    //댓글 삭제
    @Transactional
    public void delete(Long articleId, Long id) {
        Comment comment = commentRepository.findByArticleIdAndId(articleId, id).orElseThrow(() -&amp;gt;
                new IllegalArgumentException(&quot;해당 댓글이 존재하지 않습니다. id=&quot; + id));

        commentRepository.delete(comment);
    }
    //게시글을 작성한 유저인지 확인
    private static void authorizedArticleAuthor(Article article){
        String UserName= SecurityContextHolder.getContext().getAuthentication().getName();
        if(!article.getAuthor().equals(UserName)){

        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;4. 컨트롤러 작성&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;URL에 매핑을 해주고, 필요한 서비스 메서드들을 호출하자.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CommentApiController.java&lt;/p&gt;
&lt;pre id=&quot;code_1709654194596&quot; class=&quot;kotlin&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;@RequiredArgsConstructor
@RequestMapping(&quot;/api&quot;)
@RestController
public class CommentApiController {
    private final CommentService commentService;
    //댓글 생성
    @PostMapping(&quot;/articles/{id}/comments&quot;) //+현재 인증 정보를 가져오는 principal객체
    public ResponseEntity&amp;lt;Comment&amp;gt; save(@PathVariable Long id,@RequestBody AddCommentRequest request,Principal principal) {
        Comment savedComment=commentService.save(id,request, principal.getName());

        return ResponseEntity.status(HttpStatus.CREATED)
                .body(savedComment);
    }

    //댓글 읽어오기
    @GetMapping(&quot;/articles/{id}/comments&quot;)
    public List&amp;lt;Comment&amp;gt; read(@PathVariable long id) {
        return commentService.findAll(id);
    }

    //댓글 업데이트
    @PutMapping({&quot;/articles/{articleId}/comments/{id}&quot;})
    public ResponseEntity&amp;lt;Long&amp;gt; update(@PathVariable long articleId, @PathVariable Long id, @RequestBody UpdateCommentRequest dto) {
        commentService.update(articleId, id, dto);
        return ResponseEntity.ok(id);
    }

    //댓글 삭제
    @DeleteMapping(&quot;/articles/{articleId}/comments/{id}&quot;)
    public ResponseEntity&amp;lt;Long&amp;gt; delete(@PathVariable long articleId, @PathVariable Long id) {
        commentService.delete(articleId, id);
        return ResponseEntity.ok(id);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기능 구현은 끝&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;5.뷰 작성&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5-1. 댓글을 보여주기 위해 GET 요청이 오면, 응답을 위한 dto가 필요하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;CommentResponse.java&lt;/p&gt;
&lt;pre id=&quot;code_1709654194597&quot; class=&quot;kotlin&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;@RequiredArgsConstructor
@Getter
public class CommentResponse {
    private Long id;
    private String comment;
    private LocalDateTime createdAt = LocalDateTime.now();
    private LocalDateTime modifiedAt = LocalDateTime.now();
    private String nickname;
    private Long userId;
    private Long ArticleId;

    /* Entity -&amp;gt; Dto*/
    public CommentResponse(Comment comment) {
        this.id = comment.getId();
        this.comment = comment.getComment();
        this.createdAt = comment.getCreatedDate();
        this.modifiedAt = comment.getModifiedDate();
        this.ArticleId = comment.getArticle().getId();
        this.nickname = comment.getUser().getNickname();
        this.userId = comment.getUser().getId();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5-2.&lt;span&gt;&amp;nbsp;&lt;/span&gt;뷰에게 데이터를 전달하기 위한 객체이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ArticleListViewResponse.java&lt;/p&gt;
&lt;pre id=&quot;code_1709654194597&quot; class=&quot;kotlin&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;@Getter
@NoArgsConstructor
public class ArticleViewResponse {
    private Long id;
    private String title;
    private String content;
    private LocalDateTime createdAt;
    private String author;

    private List&amp;lt;CommentResponse&amp;gt; comments;

    public ArticleViewResponse(Article article){
        this.id= article.getId();
        this.title=article.getTitle();
        this.content= article.getContent();
        this.createdAt = LocalDateTime.now();
        this.author=article.getAuthor();
        this.comments = article.getComments().stream().map(CommentResponse::new).collect(Collectors.toList());
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Article 정보만 전달하던 기존에서 comments를 추가하였다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5-3.article.html 파일에&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;댓글 부분을 추가한다.&lt;/p&gt;
&lt;pre id=&quot;code_1709654194598&quot; class=&quot;dust&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html xmlns:th=&quot;http://www.thymeleaf.org&quot;&amp;gt;
&amp;lt;head&amp;gt;
    &amp;lt;meta charset=&quot;UTF-8&quot;&amp;gt;
    &amp;lt;title&amp;gt;블로그 글&amp;lt;/title&amp;gt;
    &amp;lt;link rel=&quot;stylesheet&quot; href=&quot;https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css&quot;&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
&amp;lt;div class=&quot;p-5 mb-5 text-center bg-light&quot;&amp;gt;
    &amp;lt;h1 class=&quot;mb-3&quot; th:style=&quot;'font-family: \'Segoe UI\', Tahoma, Geneva, Verdana, sans-serif;'&quot;&amp;gt;My Blog&amp;lt;/h1&amp;gt;
    &amp;lt;h4 class=&quot;mb-3&quot;&amp;gt;블로그에 오신 것을 환영합니다.&amp;lt;/h4&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;input type=&quot;hidden&quot; id=&quot;article-id&quot; th:value=&quot;${article.id}&quot;&amp;gt;
&amp;lt;div class=&quot;container mt-5&quot;&amp;gt;
    &amp;lt;div class=&quot;row&quot;&amp;gt;
        &amp;lt;div class=&quot;col-lg-8&quot;&amp;gt;
            &amp;lt;article th:classappend=&quot;'article-section'&quot;&amp;gt;
                &amp;lt;!-- 블로그 글 id 추가 --&amp;gt;
                &amp;lt;header class=&quot;mb-4&quot;&amp;gt;
                    &amp;lt;h1 class=&quot;fw-bolder mb-1&quot; th:text=&quot;${article.title}&quot;&amp;gt;&amp;lt;/h1&amp;gt;
                    &amp;lt;div class=&quot;text-muted fst-italic mb-2&quot; th:text=&quot;|Posted on ${#temporals.format(article.createdAt, 'yyyy-MM-dd HH:mm')} By ${article.author}|&quot;&amp;gt;&amp;lt;/div&amp;gt;
                &amp;lt;/header&amp;gt;
                &amp;lt;hr class=&quot;section-divider&quot;&amp;gt;
                &amp;lt;hr class=&quot;section-divider&quot; th:remove=&quot;tag&quot;/&amp;gt;
                &amp;lt;section class=&quot;mb-5&quot;&amp;gt;
                    &amp;lt;p class=&quot;fs-5 mb-4&quot; th:text=&quot;${article.content}&quot;&amp;gt;&amp;lt;/p&amp;gt;
                &amp;lt;/section&amp;gt;
            &amp;lt;/article&amp;gt;
            &amp;lt;!-- 글 수정, 삭제 버튼 --&amp;gt;
            &amp;lt;button type=&quot;button&quot; id=&quot;modify-btn&quot; th:onclick=&quot;|location.href='@{/new-article?id={articleId}(articleId=${article.id})}'|&quot;
                    class=&quot;btn btn-primary btn-sm&quot;&amp;gt;수정&amp;lt;/button&amp;gt;
            &amp;lt;button type=&quot;button&quot; id=&quot;delete-btn&quot; class=&quot;btn btn-secondary btn-sm&quot;&amp;gt;삭제&amp;lt;/button&amp;gt;

            &amp;lt;hr class=&quot;section-divider&quot;&amp;gt;
            &amp;lt;hr class=&quot;section-divider&quot; th:remove=&quot;tag&quot;/&amp;gt;
            &amp;lt;!-- 댓글 섹션 시작 --&amp;gt;
            &amp;lt;section id=&quot;comments-section&quot; th:style=&quot;'margin-top: 20px;'&quot;&amp;gt;
                &amp;lt;div id=&quot;comments-container&quot;&amp;gt;
                    &amp;lt;!-- 댓글 목록이 여기에 동적으로 추가될 것입니다. --&amp;gt;
                    &amp;lt;table class=&quot;table&quot;&amp;gt;
                        &amp;lt;thead&amp;gt;
                        &amp;lt;tr&amp;gt;&amp;lt;th&amp;gt;Comments&amp;lt;/th&amp;gt;&amp;lt;/tr&amp;gt;
                        &amp;lt;/thead&amp;gt;
                        &amp;lt;tbody&amp;gt;
                        &amp;lt;!-- 각 댓글을 표 형식으로 표시 --&amp;gt;
                        &amp;lt;tr th:each=&quot;item : ${comments}&quot;&amp;gt;
                            &amp;lt;td th:text=&quot;${item.comment}&quot;&amp;gt;&amp;lt;/td&amp;gt; &amp;lt;!-- 댓글 내용 --&amp;gt;
                            &amp;lt;td th:text=&quot;${item.nickname}&quot;&amp;gt;&amp;lt;/td&amp;gt; &amp;lt;!-- 댓글 작성자 --&amp;gt;
                            &amp;lt;td th:text=&quot;${#temporals.format(item.modifiedAt, 'yyyy-MM-dd HH:mm')}&quot;&amp;gt;&amp;lt;/td&amp;gt; &amp;lt;!-- 댓글 작성자 --&amp;gt;
                        &amp;lt;/tr&amp;gt;
                        &amp;lt;/tbody&amp;gt;
                    &amp;lt;/table&amp;gt;
                &amp;lt;/div&amp;gt;
                &amp;lt;!-- 댓글 작성 폼 --&amp;gt;
                &amp;lt;form id=&quot;comment-form&quot;&amp;gt;
                    &amp;lt;div class=&quot;form-group&quot;&amp;gt;
                        &amp;lt;label for=&quot;comment&quot;&amp;gt;댓글 추가:&amp;lt;/label&amp;gt;
                        &amp;lt;textarea class=&quot;form-control&quot; id=&quot;comment&quot; rows=&quot;3&quot;&amp;gt;&amp;lt;/textarea&amp;gt;
                    &amp;lt;/div&amp;gt;
                    &amp;lt;button type=&quot;button&quot; class=&quot;btn btn-primary&quot; id=&quot;create-comment-btn&quot;&amp;gt;댓글 작성&amp;lt;/button&amp;gt;
                &amp;lt;/form&amp;gt;
            &amp;lt;/section&amp;gt;
            &amp;lt;!-- 댓글 섹션 끝 --&amp;gt;
        &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
&amp;lt;/div&amp;gt;
&amp;lt;script src=&quot;/js/comment.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;script src=&quot;/js/article.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;script src=&quot;https://code.jquery.com/jquery-3.6.0.min.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;5-4. 자바스크립트로&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;버튼을 눌렀을 때 댓글 생성 API에 관련 요청을 보내준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;comment.js&lt;/p&gt;
&lt;pre id=&quot;code_1709654194602&quot; class=&quot;javascript&quot; style=&quot;background-color: #f8f8f8; color: #383a42;&quot; data-ke-type=&quot;codeblock&quot; data-ke-language=&quot;bash&quot;&gt;&lt;code&gt;const createCommentButton = document.getElementById('create-comment-btn');

if (createCommentButton) {
    createCommentButton.addEventListener('click', function(event) {
        event.preventDefault();
        alert(&quot;success&quot;);

        const data = {
            postsId: $('#article-id').val(),
            comment: $('#comment').val()
        };

        if (!data.comment || data.comment.trim() === &quot;&quot;) {
            alert(&quot;공백 또는 입력하지 않은 부분이 있습니다.&quot;);
            return false;
        } else {
            body = JSON.stringify({
                        comment: $('#comment').val()
                    });
                    function success() {
                        alert('등록 완료되었습니다.');
                        location.replace('/articles/'+data.postsId);
                    };
                    function fail() {
                        alert('등록 실패했습니다.');
                        location.replace('/articles/'+data.postsId);
                    };
                    httpRequest('POST', '/api/articles/' + data.postsId + '/comments', body, success, fail);
        }
    });
}
// 쿠키를 가져오는 함수
 function getCookie(key) {
     var result = null;
     var cookie = document.cookie.split(';');
     cookie.some(function (item) {
         item = item.replace(' ', '');

         var dic = item.split('=');

         if (key === dic[0]) {
             result = dic[1];
             return true;
         }
     });

     return result;
 }
function httpRequest(method, url, body, success, fail) {
    alert(&quot;success&quot;);

    fetch(url, {
        method: method,
        headers: { // 로컬 스토리지에서 액세스 토큰 값을 가져와 헤더에 추가
            Authorization: 'Bearer ' + localStorage.getItem('access_token'),
            'Content-Type': 'application/json',
        },
        body: body,
    }).then(response =&amp;gt; {
        if (response.status === 200 || response.status === 201) {
            return success();
        }
        const refresh_token = getCookie('refresh_token');
        if (response.status === 401 &amp;amp;&amp;amp; refresh_token) {
            fetch('/api/token', {
                method: 'POST',
                headers: {
                    Authorization: 'Bearer ' + localStorage.getItem('access_token'),
                    'Content-Type': 'application/json',
                },
                body: JSON.stringify({
                    refreshToken: getCookie('refresh_token'),
                }),
            })
                .then(res =&amp;gt; {
                    if (res.ok) {
                        return res.json();
                    }
                })
                .then(result =&amp;gt; { // 재발급이 성공하면 로컬 스토리지값을 새로운 액세스 토큰으로 교체
                    localStorage.setItem('access_token', result.accessToken);
                    httpRequest(method, url, body, success, fail);
                })
                .catch(error =&amp;gt; fail());
        } else {
            return fail();
        }
    });
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;댓글 작성.png&quot; data-origin-width=&quot;977&quot; data-origin-height=&quot;677&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bH2cRw/btsFAf3IVMO/XknopxfBK3rgkiUdu6HTvk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bH2cRw/btsFAf3IVMO/XknopxfBK3rgkiUdu6HTvk/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bH2cRw/btsFAf3IVMO/XknopxfBK3rgkiUdu6HTvk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbH2cRw%2FbtsFAf3IVMO%2FXknopxfBK3rgkiUdu6HTvk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;708&quot; height=&quot;491&quot; data-filename=&quot;댓글 작성.png&quot; data-origin-width=&quot;977&quot; data-origin-height=&quot;677&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;댓글을 단 모습이다.&lt;/p&gt;</description>
      <category>프로젝트/스프링부트</category>
      <author>코오오 코오</author>
      <guid isPermaLink="true">https://fightingway.tistory.com/45</guid>
      <comments>https://fightingway.tistory.com/45#entry45comment</comments>
      <pubDate>Wed, 6 Mar 2024 00:56:53 +0900</pubDate>
    </item>
    <item>
      <title>SpringBoot 게시판 만들기-1. CRUD, 로그인 기능 구현</title>
      <link>https://fightingway.tistory.com/44</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;기본적인 CRUD 기능이 있는 게시판으로, 웹 애플리케이션과 SpringBoot에 대한 기초를 다지기 위한 프로젝트를 작성한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a title=&quot;스프링 부트 3 백엔드 개발자 되기: 자바 편&quot; href=&quot;https://product.kyobobook.co.kr/detail/S000201766024&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot;&gt; &lt;span style=&quot;color: #000000; text-align: center;&quot;&gt;스프링 부트 3 백엔드 개발자 되기: 자바 편&lt;/span&gt; &lt;/a&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;초기 구성을 위 책에서 상당 부분 참고했고, 추가적인 기능을 쌓아가는 식으로 진행할 계획이다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;책을 통해 완성할 수 있는 기능은 다음과 같다.&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1.게시판 CRUD 기능&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;2. Spring Security를 이용한 로그인&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;3. OAuth2를 이용한 구글 로그인&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;4. AWS Elastic Beanstalk를 이용한 배포&amp;nbsp;&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;5. Github Action 을 이용한 CI/CD&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;여기서&lt;/span&gt;&lt;span style=&quot;color: #000000;&quot;&gt;1. 게시글에 댓글 추가 &lt;br /&gt;2. 게시글 검색 &lt;br /&gt;3. 게시글 페이징&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;4. 게시글 조회수&lt;br /&gt;5. Spring Security를 이용한 로그인과 OAuth2를 이용한 구글 로그인 중 선택하여 로그인&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;6. 그 외 회원 정보 입력&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;같은 기능을 추가할 예정이다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000;&quot;&gt;책을 통해 아래와 같은 결과를 얻을 수 있다.&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;&lt;span style=&quot;color: #000000;&quot;&gt;로그인 화면&lt;/span&gt;&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;화면 캡처 2024-03-01 195408.png&quot; data-origin-width=&quot;1173&quot; data-origin-height=&quot;825&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/cDY6jw/btsFpRQIKqK/HDdserCzMe0myhcgEAIDI1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/cDY6jw/btsFpRQIKqK/HDdserCzMe0myhcgEAIDI1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/cDY6jw/btsFpRQIKqK/HDdserCzMe0myhcgEAIDI1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FcDY6jw%2FbtsFpRQIKqK%2FHDdserCzMe0myhcgEAIDI1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1173&quot; height=&quot;825&quot; data-filename=&quot;화면 캡처 2024-03-01 195408.png&quot; data-origin-width=&quot;1173&quot; data-origin-height=&quot;825&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;구글 연동을 통한 로그인&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_구글연동된모습.png&quot; data-origin-width=&quot;1480&quot; data-origin-height=&quot;741&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/dK9Ng0/btsFn9qIrZw/aFhXNKsjIXE6VFwbchLlOK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/dK9Ng0/btsFn9qIrZw/aFhXNKsjIXE6VFwbchLlOK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/dK9Ng0/btsFn9qIrZw/aFhXNKsjIXE6VFwbchLlOK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FdK9Ng0%2FbtsFn9qIrZw%2FaFhXNKsjIXE6VFwbchLlOK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1480&quot; height=&quot;741&quot; data-filename=&quot;edited_구글연동된모습.png&quot; data-origin-width=&quot;1480&quot; data-origin-height=&quot;741&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;로그인 후 보이는 게시글 리스트.&lt;/b&gt; 레이아웃 부분에서 기존 코드에서 살짝 수정을 거쳤다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;글 리스트.png&quot; data-origin-width=&quot;1522&quot; data-origin-height=&quot;762&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/zqkgQ/btsFs07fRRS/xd7lQKfABalglQ3unqKoDK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/zqkgQ/btsFs07fRRS/xd7lQKfABalglQ3unqKoDK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/zqkgQ/btsFs07fRRS/xd7lQKfABalglQ3unqKoDK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FzqkgQ%2FbtsFs07fRRS%2Fxd7lQKfABalglQ3unqKoDK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1522&quot; height=&quot;762&quot; data-filename=&quot;글 리스트.png&quot; data-origin-width=&quot;1522&quot; data-origin-height=&quot;762&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;게시글 작성 화면&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;글쓰기.png&quot; data-origin-width=&quot;1473&quot; data-origin-height=&quot;812&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/XXtL9/btsFnWybrpQ/sTKsyvuIA0vIWtKT6YRxPK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/XXtL9/btsFnWybrpQ/sTKsyvuIA0vIWtKT6YRxPK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/XXtL9/btsFnWybrpQ/sTKsyvuIA0vIWtKT6YRxPK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FXXtL9%2FbtsFnWybrpQ%2FsTKsyvuIA0vIWtKT6YRxPK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1473&quot; height=&quot;812&quot; data-filename=&quot;글쓰기.png&quot; data-origin-width=&quot;1473&quot; data-origin-height=&quot;812&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;게시글을 작성하면 보이는 화면.&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;댓글 영역이 있긴 한데 기능을 아직 구현하진 않았다.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;글 조회.png&quot; data-origin-width=&quot;1160&quot; data-origin-height=&quot;857&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bLgBVp/btsFwBeNaJd/7ryC4nwVmIj3yG19KkigW1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bLgBVp/btsFwBeNaJd/7ryC4nwVmIj3yG19KkigW1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bLgBVp/btsFwBeNaJd/7ryC4nwVmIj3yG19KkigW1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbLgBVp%2FbtsFwBeNaJd%2F7ryC4nwVmIj3yG19KkigW1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1160&quot; height=&quot;857&quot; data-filename=&quot;글 조회.png&quot; data-origin-width=&quot;1160&quot; data-origin-height=&quot;857&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;새 글이 추가된 모습.&lt;/b&gt; 작성자를 표현하는 방법이 이메일 뿐이다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;글 쓴 후.png&quot; data-origin-width=&quot;1457&quot; data-origin-height=&quot;818&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/WALNc/btsFoKqCa7t/4K1OXIYuo0i8FeZ602upT1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/WALNc/btsFoKqCa7t/4K1OXIYuo0i8FeZ602upT1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/WALNc/btsFoKqCa7t/4K1OXIYuo0i8FeZ602upT1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FWALNc%2FbtsFoKqCa7t%2F4K1OXIYuo0i8FeZ602upT1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1457&quot; height=&quot;818&quot; data-filename=&quot;글 쓴 후.png&quot; data-origin-width=&quot;1457&quot; data-origin-height=&quot;818&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;AWS Elasticbeanstalk를 통해 배포한 후 모습&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;책을 따라했을 뿐인데도 알 수 없는 오류가 많아 생각보다 오래 걸렸다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;아직 공부가 부족한 탓에 무엇 때문이었는지는 모르겠고, 그냥 안된다.. 안된다... 하다가 결국 새 애플리케이션을 생성해서 해결했다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;edited_AWS 배포 경험.png&quot; data-origin-width=&quot;1471&quot; data-origin-height=&quot;557&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/bzRhVw/btsFoH1IzCK/fZkBG5bJHAjuT3SnjPeDMk/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/bzRhVw/btsFoH1IzCK/fZkBG5bJHAjuT3SnjPeDMk/img.png&quot; data-alt=&quot;배포 후 한 달 방치해놨더니 별 거 한 것도 없는데 5만원이 청구되었다... 따라서 현재는 삭제.&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/bzRhVw/btsFoH1IzCK/fZkBG5bJHAjuT3SnjPeDMk/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FbzRhVw%2FbtsFoH1IzCK%2FfZkBG5bJHAjuT3SnjPeDMk%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;1471&quot; height=&quot;557&quot; data-filename=&quot;edited_AWS 배포 경험.png&quot; data-origin-width=&quot;1471&quot; data-origin-height=&quot;557&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;배포 후 한 달 방치해놨더니 별 거 한 것도 없는데 5만원이 청구되었다... 따라서 현재는 삭제.&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;코드&lt;/p&gt;
&lt;p style=&quot;text-align: left;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://github.com/saaut/springbootProject_myBlog&quot; target=&quot;_blank&quot; rel=&quot;noopener&amp;nbsp;noreferrer&quot;&gt;https://github.com/saaut/springbootProject_myBlog&lt;/a&gt;&lt;/p&gt;</description>
      <category>프로젝트/스프링부트</category>
      <author>코오오 코오</author>
      <guid isPermaLink="true">https://fightingway.tistory.com/44</guid>
      <comments>https://fightingway.tistory.com/44#entry44comment</comments>
      <pubDate>Mon, 4 Mar 2024 19:05:37 +0900</pubDate>
    </item>
    <item>
      <title>Dynamic Programming-Floyd Warshall 알고리즘</title>
      <link>https://fightingway.tistory.com/38</link>
      <description>&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;Dynamic Programming(동적 알고리즘)이란?&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;최적화 문제를 해결하는 알고리즘&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1.입력 크기가 작은 '부분 문제'들을 모두 해결&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2.그 해들을 이용하여 보다 '큰 크기의 부분 문제'들을 해결&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3.최종적으로 원래 주어진 입력의 문제를 해결.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Divide&amp;amp;Conquer(분할 정복 알고리즘) 방식과 구조적으로 유사하지만, 순서는 반대이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;20230509_130413374_iOS.png&quot; data-origin-width=&quot;1625&quot; data-origin-height=&quot;476&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Ta50c/btseBdKSqYA/NYWEjr3OdDS9m2zCM9jNRK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Ta50c/btseBdKSqYA/NYWEjr3OdDS9m2zCM9jNRK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Ta50c/btseBdKSqYA/NYWEjr3OdDS9m2zCM9jNRK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FTa50c%2FbtseBdKSqYA%2FNYWEjr3OdDS9m2zCM9jNRK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;778&quot; height=&quot;228&quot; data-filename=&quot;20230509_130413374_iOS.png&quot; data-origin-width=&quot;1625&quot; data-origin-height=&quot;476&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;거기에 더해, 동적 계획 알고리즘은 B와 C의 해를 구하는 데 E와 F의 해 모두를 이용한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;분할 정복 알고리즘&lt;/b&gt;의 경우,&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;D,E,F,G는 각각 더 이상 분할할 수 없는 부분 문제들이다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;D와 E의 해를 취합하여 B의 해를 구하고,&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;F와 G의 해를 취합하여 C의 해를 구하고,&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;B와 C의 해를 취합하여 A를 구한다...&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;동적 계획 알고리즘&lt;/b&gt;의 경우,&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;먼저 최소 단위의 부분 문제 D, E, F, G의 해를 각각 구하고,&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;D, E, F의 해를 이용하여 B의 해를 구한다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;E, F, G의 해를 이용하여 C의 해를 구한다.&lt;/p&gt;
&lt;p style=&quot;color: #333333; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;B와 C의 해를 구하는데 있어 E와 F의 해 모두를 이용했다는 점에서 차이를 볼 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;b&gt;동적 계획 알고리즘의 예시&lt;/b&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;1.모든 쌍 최단 경로 문제&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-각 쌍의 점 사이의 최단 경로를 찾는 문제&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;20230509_131007075_iOS.png&quot; data-origin-width=&quot;584&quot; data-origin-height=&quot;224&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/8BMEP/btseyM8zYZR/qgyCWX6dQhJdE8paVxu6ak/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/8BMEP/btseyM8zYZR/qgyCWX6dQhJdE8paVxu6ak/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/8BMEP/btseyM8zYZR/qgyCWX6dQhJdE8paVxu6ak/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F8BMEP%2FbtseyM8zYZR%2FqgyCWX6dQhJdE8paVxu6ak%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;433&quot; height=&quot;166&quot; data-filename=&quot;20230509_131007075_iOS.png&quot; data-origin-width=&quot;584&quot; data-origin-height=&quot;224&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; text-align: center;&quot;&gt;A와 B 사이의 최단 경로를 찾는 문제가 있다. 그런데 그래프에서 둘이 이어지는 경로가 하나가 아니라, 다른 노드들에 의해 N개가 된다면? 컴퓨터는 모든 Path를 다 찾아서 비교하게 될 것이다. Time Complexity O(n^4)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; text-align: center;&quot;&gt;-Idea&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; text-align: center;&quot;&gt;(1)그래프에 3개의 점이 있는 경우, 점 A에서 점 B까지의 최단 경로를 찾으려면, 2가지 경로, 즉 점 A에서 B로 직접 가는 경로 하나와, 점 1을 경유하는 경로 중에서 짧은 것을 선택하면 된다.(n번 반복)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;color: #000000; text-align: center;&quot;&gt;(2) 그래프에 4개의 점이 있는 경우, A에서 B까지의 최단 경로를 찾을 때 직접 가는 경로 하나와, 점을 하나만 지나는 경로 n개와, 점 2개를 지나는 경로를 선택할 수 있다. 이 때, 점 2개를 지나는 경로의 경우 점 1개를 지나는 경로에 대한 연산과 겹치기 때문에, 반복 작업을 하지 않고 넘어간다. -&amp;gt;모든 경로를 여러 번 계산할 필요가 없다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(3) 이 때, starting point와 destination을 고정해서 생각하지 말고, 그래프에 존재하는 점을 고정해서 생각하라.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그래프에 존재하는 점 하나에서, 다른 점까지의 최소 경로를 이차원 배열 형태로 출력할 수 있다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;20230509_132528573_iOS.png&quot; data-origin-width=&quot;1222&quot; data-origin-height=&quot;465&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/1nnf2/btseBJiDGk8/U9m4jkvTLB1IbMQYYVIAG1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/1nnf2/btseBJiDGk8/U9m4jkvTLB1IbMQYYVIAG1/img.png&quot; data-alt=&quot;그래프의 경로를 이차원 배열 형태로 출력하기&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/1nnf2/btseBJiDGk8/U9m4jkvTLB1IbMQYYVIAG1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F1nnf2%2FbtseBJiDGk8%2FU9m4jkvTLB1IbMQYYVIAG1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;639&quot; height=&quot;243&quot; data-filename=&quot;20230509_132528573_iOS.png&quot; data-origin-width=&quot;1222&quot; data-origin-height=&quot;465&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그래프의 경로를 이차원 배열 형태로 출력하기&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(4)그리고 존재하는 경로를 통해서, 정해지지 않은 경로의 거리를 구할 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1-&amp;gt;5로 가는 방법이 현재 존재하지 않지만, 2를 거치는 방법으로 거리 1만큼 걸려 갈 수 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(5)이를 여러 번 반복해서 배열을 업데이트 해준다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Dijkstra와 비슷한 느낌이 들기도 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이처럼 문제 해결 과정에 반복 연산이 여러 번 있으면 동적 알고리즘이라 표현한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;피보나치 수열도 이와 같은 계열이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;20230509_134040124_iOS.png&quot; data-origin-width=&quot;1668&quot; data-origin-height=&quot;856&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/FQITE/btseAUkqFIs/fJxuw5Qqgg4BhVvuunqYy0/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/FQITE/btseAUkqFIs/fJxuw5Qqgg4BhVvuunqYy0/img.png&quot; data-alt=&quot;정리하면 위와 같다&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/FQITE/btseAUkqFIs/fJxuw5Qqgg4BhVvuunqYy0/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FFQITE%2FbtseAUkqFIs%2FfJxuw5Qqgg4BhVvuunqYy0%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;694&quot; height=&quot;356&quot; data-filename=&quot;20230509_134040124_iOS.png&quot; data-origin-width=&quot;1668&quot; data-origin-height=&quot;856&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;정리하면 위와 같다&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-구현 방법&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;플로이드-워샬 알고리즘&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-warshall은 그래프에서 모든 쌍의 '경로 존재 여부'를 찾아내는 동적 계획 알고리즘을 제안했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-Floyd는 이를 변형하여 모든 쌍의 '최단 경로'를 찾는 알고리즘을 고안했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-따라서 모든 쌍의 최단 경로를 찾는 동적 계획 알고리즘을 플로이드-워샬 알고리즘이라 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-플로이드-워샬 알고리즘의 시간복잡도는 O(n^3)으로 다익스트라 알고리즘을 n번 사용할때의 시간복잡도와 동일하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-그러나 플로이드 알고리즘은 매우 간단하여 다익스트라 알고리즘을 사용하는 것보다 효율적이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;A에서 B로 직접 가는 경로, A에서 점 1을 경유하여 B로 가는 경로가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;B에서 C로 직접 가는 경로, B에서 점 1을 경유하여 C로 가는 경로가 있다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 식으로 모든 쌍에 대하여, 직접 가는 경로와 1을 경유하는 경로를 비교한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;그 다음엔 점 2를 경유하여 가는 거리와 비교한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이때, 점 2는 1을 경유하는 경로를 거친다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이런 식으로 모든 쌍에 대하여 두 개의 점을 경유하는 경로를 비교한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;n번 반복하여 가장 짧은 것을 고른다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-수행 과정&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;배열 D를 만들어 갱신해 나간다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;20230509_132528573_iOS.png&quot; data-origin-width=&quot;1222&quot; data-origin-height=&quot;465&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/pdfgY/btsjlkT0q8E/HjGiWOZMHhBFVfLbPzHTMK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/pdfgY/btsjlkT0q8E/HjGiWOZMHhBFVfLbPzHTMK/img.png&quot; data-alt=&quot;그래프와 배열 D&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/pdfgY/btsjlkT0q8E/HjGiWOZMHhBFVfLbPzHTMK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FpdfgY%2FbtsjlkT0q8E%2FHjGiWOZMHhBFVfLbPzHTMK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;707&quot; height=&quot;269&quot; data-filename=&quot;20230509_132528573_iOS.png&quot; data-origin-width=&quot;1222&quot; data-origin-height=&quot;465&quot;/&gt;&lt;/span&gt;&lt;figcaption&gt;그래프와 배열 D&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위는 배열 D를 갱신하는 과정이다. 직접 가는 경로와, 점 1을 거쳐서 가는 경로 중에서 어떤 값이 더 작은지 비교하고, 갱신한다.&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;20230611_044328385_iOS.png&quot; data-origin-width=&quot;1973&quot; data-origin-height=&quot;1086&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/2O6mN/btsjpEcYbvX/a1hLr5c7wAnd3RlTgiVI00/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/2O6mN/btsjpEcYbvX/a1hLr5c7wAnd3RlTgiVI00/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/2O6mN/btsjpEcYbvX/a1hLr5c7wAnd3RlTgiVI00/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2F2O6mN%2FbtsjpEcYbvX%2Fa1hLr5c7wAnd3RlTgiVI00%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;734&quot; height=&quot;404&quot; data-filename=&quot;20230611_044328385_iOS.png&quot; data-origin-width=&quot;1973&quot; data-origin-height=&quot;1086&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;20230611_045223061_iOS.png&quot; data-origin-width=&quot;1839&quot; data-origin-height=&quot;1025&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/nPEs2/btsjwsiJBMH/g70kNDosfEyoTGK7hzuklK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/nPEs2/btsjwsiJBMH/g70kNDosfEyoTGK7hzuklK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/nPEs2/btsjwsiJBMH/g70kNDosfEyoTGK7hzuklK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FnPEs2%2FbtsjwsiJBMH%2Fg70kNDosfEyoTGK7hzuklK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;707&quot; height=&quot;394&quot; data-filename=&quot;20230611_045223061_iOS.png&quot; data-origin-width=&quot;1839&quot; data-origin-height=&quot;1025&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;k를 1씩 증가시켜가며 n번 반복한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-시간복잡도&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;k n번반복&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2차원 배열 D에 있어 행n번 반복, 열 n 번 반복&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;총 n^3번 반복&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;O(n^3)&lt;/p&gt;</description>
      <category>강의내용 복습/컴퓨터 알고리즘</category>
      <author>코오오 코오</author>
      <guid isPermaLink="true">https://fightingway.tistory.com/38</guid>
      <comments>https://fightingway.tistory.com/38#entry38comment</comments>
      <pubDate>Sun, 11 Jun 2023 12:31:57 +0900</pubDate>
    </item>
    <item>
      <title>서버에서 로그아웃 깜빡했을때</title>
      <link>https://fightingway.tistory.com/37</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://bewan.tistory.com/50&quot; target=&quot;_blank&quot;&gt;&lt;span&gt;https://bewan.tistory.com/50&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;&lt;figure data-ke-type=&quot;opengraph&quot; data-og-title=&quot;다른사용자 강제 logout 시키기&quot; data-ke-align=&quot;alignCenter&quot; data-og-description=&quot;운영상의 이유로 현재 접속중인 사용자들을(또는 특정 사용자) 시스템에서 logout 시킬 경우가 필요한 경우가 있다. 이와같이 부득이하게 다른 사용자(혹은 내 계정)을 logout 시키고자 할때 아래 &quot; data-og-host=&quot;bewan8.com&quot; data-og-source-url=&quot;https://bewan8.com/50&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/bucbj9/hySHbNrjUR/8MbrBFiwBVegR9izvrazk1/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800&quot; data-og-url=&quot;https://bewan8.com/50&quot;&gt;&lt;a href=&quot;https://bewan8.com/50&quot; target=&quot;_blank&quot; data-source-url=&quot;https://bewan8.com/50&quot;&gt;&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/bucbj9/hySHbNrjUR/8MbrBFiwBVegR9izvrazk1/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800')&quot;&gt; &lt;/div&gt;&lt;div class=&quot;og-text&quot;&gt;&lt;p class=&quot;og-title&quot;&gt;다른사용자 강제 logout 시키기&lt;/p&gt;&lt;p class=&quot;og-desc&quot;&gt;운영상의 이유로 현재 접속중인 사용자들을(또는 특정 사용자) 시스템에서 logout 시킬 경우가 필요한 경우가 있다. 이와같이 부득이하게 다른 사용자(혹은 내 계정)을 logout 시키고자 할때 아래 &lt;/p&gt;&lt;p class=&quot;og-host&quot;&gt;bewan8.com&lt;/p&gt;&lt;/div&gt;&lt;/a&gt;&lt;/figure&gt;&lt;p data-ke-size=&quot;size16&quot;&gt;who&lt;br&gt;ps -dN|grep pts/0&lt;br&gt;kill -9 12345&lt;/p&gt;</description>
      <category>리눅스</category>
      <author>코오오 코오</author>
      <guid isPermaLink="true">https://fightingway.tistory.com/37</guid>
      <comments>https://fightingway.tistory.com/37#entry37comment</comments>
      <pubDate>Mon, 15 May 2023 13:06:57 +0900</pubDate>
    </item>
    <item>
      <title>원격 리눅스 서버에서 파이썬 파일 실행하기</title>
      <link>https://fightingway.tistory.com/36</link>
      <description>&lt;h3 data-ke-size=&quot;size23&quot;&gt;1.원격 서버 연결&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;2.python 코드 전송(FTP, SCP or Git)&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;3.cd 명령을 사용하여 python코드를 업로드한 디렉토리로 이동&lt;/h3&gt;
&lt;pre id=&quot;code_1684122350335&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;cd /path/to/directory&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000; text-align: start;&quot;&gt;설치 종속성(필요한 경우): 코드가 외부 라이브러리 또는 패키지에 의존하는 경우 원격 서버에 설치해야 할 수 있습니다. Pip for Python 패키지와 같은 서버 운영 체제에 적합한 패키지 관리자를 통해 설치&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000; text-align: start;&quot;&gt;4.python 명령을 통해 실행&lt;/span&gt;&lt;/h3&gt;
&lt;pre id=&quot;code_1684122398259&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;python3 your_script.py&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000; text-align: start;&quot;&gt;코드 실행 모니터링: 코드에 따라 포그라운드 또는 백그라운드에서 실행될 수 있습니다. 코드가 예상대로 실행되는지 확인하고 필요에 따라 출력 또는 로그를 모니터링합니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 data-ke-size=&quot;size23&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000; text-align: start;&quot;&gt;5.중단하기&lt;/span&gt;&lt;/h3&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000; text-align: start;&quot;&gt;(1)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000; text-align: start;&quot;&gt;키보드 인터럽트: Python 코드가 명령줄의 포그라운드에서 실행 중인 경우 일반적으로 Ctrl + C를 눌러 코드를 중지할 수 있습니다. 그러면 Python 프로세스에 키보드 인터럽트 신호가 전송되어 프로세스가 종료됩니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000; text-align: start;&quot;&gt;(2)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000; text-align: start;&quot;&gt;프로세스 종료: Python 코드가 백그라운드에서 실행 중이거나 별도의 프로세스로 실행 중인 경우, Python 프로세스의 프로세스 ID(PID)를 찾고 kill 명령을 사용하여 종료할 수 있습니다. 다음은 특정 PID를 사용하여 프로세스를 종료하는 방법의 예입니다&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1684122471383&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;kill PID&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000; text-align: start;&quot;&gt;PID를 Python 프로세스의 실제 프로세스 ID로 바꿉니다. PID는 ps 또는 top과 같은 도구를 사용하거나 프로세스 이름을 검색하여 찾을 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000; text-align: start;&quot;&gt;(3)&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000; text-align: start;&quot;&gt;정상 종료: Python 코드가 정상 종료를 처리하도록 설계된 경우 코드 실행을 중지하는 특정 메커니즘을 구현했을 수 있습니다. 이 경우 코드에서 특정 신호를 보내거나 특정 이벤트를 트리거하여 전체 종료를 시작할 수 있습니다. 코드를 정상적으로 중지하는 방법을 결정하려면 코드의 특정 구현을 참조하십시오.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;br /&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000; text-align: start;&quot;&gt;원격 서버에서 Python 코드를 실행하는 경우 서버에 대한 SSH 연결을 설정하고 위에서 언급한 필요한 명령을 실행하여 코드 실행을 중지해야 할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000; text-align: start;&quot;&gt;6.python 패키지가 필요한 경우&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000; text-align: start;&quot;&gt;리눅스에서 pip 명령어를 사용해서 설치 가능&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #fdfdfd; color: #000000; text-align: start;&quot;&gt;(1) pip 설치 확인&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1684122941475&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;pip --version&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(2) pip 설치&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;필요한 경우, 서&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;버의 운영 체제 및 Python 버전에 적합한 설치 지침에 따라 설치할 수 있습니다. 이 지침은 서버 환경에 따라 다를 수 있습니다. 예를 들어 Ubuntu 또는 Debian 기반 시스템에서 다음 명령을 사용하여 Python 3용 &lt;/span&gt;pip&lt;span style=&quot;color: #374151; text-align: left;&quot;&gt;를 설치할 수 있습니다.&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1684123039773&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;sudo apt-get install python3-pip&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(3) pip 사용하여 패키지 설치&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1684123061520&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;pip install example_package&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;(4)더 이상 필요하지 않을 경우, 삭제&lt;/p&gt;
&lt;pre id=&quot;code_1684123096001&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;pip uninstall package_name&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;종속성은 자동으로 제거되지 않는다.&lt;/p&gt;</description>
      <category>리눅스</category>
      <author>코오오 코오</author>
      <guid isPermaLink="true">https://fightingway.tistory.com/36</guid>
      <comments>https://fightingway.tistory.com/36#entry36comment</comments>
      <pubDate>Mon, 15 May 2023 12:48:55 +0900</pubDate>
    </item>
    <item>
      <title>cmd에서 원격 리눅스 서버 접속하고 파일 다루기</title>
      <link>https://fightingway.tistory.com/35</link>
      <description>&lt;h2 data-ke-size=&quot;size26&quot;&gt;1.파일 업로드&lt;/h2&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;(1)윈도우에서 리눅스로 파일 전송&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;pscp -P port_number filename root@server_ip:/path&lt;/p&gt;
&lt;pre id=&quot;code_1684120219484&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;pscp -P 3000 c:\SignalUsServerTest\requirements.txt root@101.101.167.67:/root/download&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size18&quot;&gt;(2)리눅스에서 윈도우로 파일 전송&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;pscp user_name@server_ip:/path c:\path&lt;/p&gt;
&lt;pre id=&quot;code_1684120347791&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;pscp root@101.101.167.67:/root/download c:\SignalUsServerTest&lt;/code&gt;&lt;/pre&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;cmd에서 사용가능&lt;/p&gt;
&lt;p style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 style=&quot;color: #555555; text-align: start;&quot; data-ke-size=&quot;size26&quot;&gt;2.cmd에서 원격 Linux서버에 연결하기&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;ssh username@remote_server_ip&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;or&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #000000; color: #ffffff; text-align: left;&quot;&gt;ssh -&lt;/span&gt;&lt;span style=&quot;background-color: #000000; color: #ffffff; text-align: left;&quot;&gt;p&lt;/span&gt;&lt;span style=&quot;background-color: #000000; color: #ffffff; text-align: left;&quot;&gt; port_number username&lt;/span&gt;&lt;span style=&quot;background-color: #000000; color: #2e95d3; text-align: left;&quot;&gt;@remote_server_ip&lt;/span&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1684120542617&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;ssh root@101.101.167.67&lt;/code&gt;&lt;/pre&gt;
&lt;pre id=&quot;code_1684122705882&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;ssh -p 3000 root@101.101.167.67&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;3.디렉토리 이동&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;cd /path/to/directory&lt;/p&gt;
&lt;pre id=&quot;code_1684120583835&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;cd /root/download&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;4.현재 파일과 디렉토리 나열&lt;/h2&gt;
&lt;pre id=&quot;code_1684120606515&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;ls&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;5.파일 액세스, 열람&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;nano, vi, cat과 같은 텍스트 편집기 사용 가능&lt;/p&gt;
&lt;pre id=&quot;code_1684120634227&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;cat filename&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;6.파일 삭제&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;삭제하면 복구 불가&lt;/p&gt;
&lt;pre id=&quot;code_1684120651369&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;rm filename&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;7.파일 수정&lt;/h2&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;텍스트 편집기 사용 가능 nano&lt;/p&gt;
&lt;pre id=&quot;code_1684120721395&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;nano filename&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;텍스트 편집기 내에서 제공된 명령 또는 바로 가기를 사용해 수정.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;파일 편집을 마치면 저장(Ctrl+O), 종료(Ctrl+X)하면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;원격 서버의 파일도 수정 사항으로 업데이트 된다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;8.디렉토리 삭제&lt;/h2&gt;
&lt;pre id=&quot;code_1684216949986&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;rm -r dir1&lt;/code&gt;&lt;/pre&gt;
&lt;h2 data-ke-size=&quot;size26&quot;&gt;9.모든 작업 수행 후 ssh 세션 종료&lt;/h2&gt;
&lt;pre id=&quot;code_1684120694856&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;exit&lt;/code&gt;&lt;/pre&gt;</description>
      <category>리눅스</category>
      <author>코오오 코오</author>
      <guid isPermaLink="true">https://fightingway.tistory.com/35</guid>
      <comments>https://fightingway.tistory.com/35#entry35comment</comments>
      <pubDate>Mon, 15 May 2023 12:13:32 +0900</pubDate>
    </item>
    <item>
      <title>안드로이드 스튜디오 카메라 화면 캡처하기</title>
      <link>https://fightingway.tistory.com/33</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;서치하여 얻은 '카메라 기능 구현'에서&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;찍은 사진을 저장하는 단계를 제외하고, 오로지 캡처된 화면만을 이용하는 어플을 만드는 중이었다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 기존 카메라를 이용하여 얻은 이미지의 바이트 데이터를 서버로 전송하려 했으나,&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;카메라를 이용하는 과정 중 필수로 delay가 생겨 못 쓰게 되었다...&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;앱의 목표가 실시간으로 촬영-서버로 전송-서버와 소통 후 결과값 출력 이고 ,&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;실시간이니만큼 전송 중에도 촬영 화면은 계속해서 보여야 하는데&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;딜레이가 생겨 보낼 때마다 화면이 멈춰버리면&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;진정한 실시간 전송은 불가능하다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3초에 한 번 같은 느린 전송은 가능하겠지만&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;프리뷰를 보는 유저도 멈춤에 답답하고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;이미지 처리도 3초에 한 번씩만 되니까 섬세한 작업은 할 수 없다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;따라서 기존 코드를 짜다 말고 갈아엎기로 했다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;OpenCV를 이용하여 frame을 캡처하면 이를 서버로 전송할 때도 화면이 멈추지 않는다고 한다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;기존에 카메라가 실행되고 있을 때, 이 미리 보기 화면을 이용하는 코드이다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;세이브 기능은 삭제했지만, 아직 데이터를 이용하여 무언가 구현한 게 없다.&lt;/p&gt;
&lt;pre id=&quot;code_1683629132697&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;//캡처와 전송시작
    private void startCaptureImg() {
        if (null == mCameraDevice || !binding.preview.isAvailable() || null == mPreviewSize) {//카메라가 사용할 수 있는 상태인지 확인
            Log.e(TAG, &quot;mCameraDevice is null, return&quot;);
            return;
        }
        Toast.makeText(getContext(), &quot;이미지가져오기 실행&quot;, Toast.LENGTH_SHORT).show();

        assert getActivity() != null;//activity와 fragment가 잘 attach되어있고, 아직 destroy되지 않았다는 뜻
        SurfaceTexture texture = binding.preview.getSurfaceTexture();//Preview texture과 관련된 surfacetexture를 찾는다.

        assert texture !=null;//Preview texture를 사용할 수 있는 지 확인
        try {
            int width = 640;
            int height = 480;

            assert texture != null;
            ImageReader reader = ImageReader.newInstance(width, height, ImageFormat.JPEG, 1);//JPEG 형식으로 캡처된 이미지를 수신할 ImageReader 인스턴스 생성
            List&amp;lt;Surface&amp;gt; outputSurfaces = new ArrayList&amp;lt;Surface&amp;gt;(2);
            outputSurfaces.add(reader.getSurface());
            outputSurfaces.add(new Surface(texture));


            final CaptureRequest.Builder captureBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
            captureBuilder.addTarget(reader.getSurface());
            captureBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);//카메라실행을 위한 세팅. 카메라 캡처 요청에 대한 제어 모드를 자동으로 설정한다.


            ImageReader.OnImageAvailableListener readerListener = new ImageReader.OnImageAvailableListener() {//이미지를 사용할 수 있을 때 트리거되는 OnImageAvailableListener를 만든다.
                @Override
                public void onImageAvailable(ImageReader reader) {//readerListender 내부에서 캡처된 이미지를 획득
                    Image image = null;
                    try {
                        image = reader.acquireLatestImage();
                        ByteBuffer buffer = image.getPlanes()[0].getBuffer();
                        byte[] bytes = new byte[buffer.remaining()];
                        buffer.get(bytes);
                        Toast.makeText(getContext(), &quot;바이트 데이터 얻기 성공&quot;, Toast.LENGTH_SHORT).show();

                        sendImageToServer(bytes); // Call your method to send the byte data to the server
                    } finally {
                        if (image != null) {
                            image.close();
                        }
                    }
                }
            };

            HandlerThread thread = new HandlerThread(&quot;CameraPicture&quot;);
            thread.start();
            final Handler backgroudHandler = new Handler(thread.getLooper());
            reader.setOnImageAvailableListener(readerListener, backgroudHandler);

            final CameraCaptureSession.CaptureCallback captureListener = new CameraCaptureSession.CaptureCallback() {
                @Override
                public void onCaptureCompleted(CameraCaptureSession session,//캡처 완료 시 서버로 전송
                                               CaptureRequest request, TotalCaptureResult result) {
                    super.onCaptureCompleted(session, request, result);
                    startPreview();
                }

            };

            mCameraDevice.createCaptureSession(outputSurfaces, new CameraCaptureSession.StateCallback() {
                @Override
                public void onConfigured(CameraCaptureSession session) {
                    try {
                        session.capture(captureBuilder.build(), captureListener, mBackgroundHandler);
                    } catch (CameraAccessException e) {
                        e.printStackTrace();

                    }
                }

                @Override
                public void onConfigureFailed(CameraCaptureSession session) {

                }
            }, mBackgroundHandler);



        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }
    private void sendImageToServer(byte[] imageData) {
        // Implement your networking code here to send the byte data to the server
        // This can involve using libraries such as HttpURLConnection, OkHttp, Retrofit, etc.
        // Construct an HTTP request, set headers and parameters, and attach the byte data
        // to the request body before sending it to the server.
        Toast.makeText(getContext(), &quot;서버로 이미지 전송 시도&quot;, Toast.LENGTH_SHORT).show();
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;위를 활용한 전체 코드이다. 특정 앱 개발에 쓰이던 부분은 삭제했지만 대충 해서 쓸 데 없는 부분이 많을 것이고..., 카메라 부분 외에는 많이 조잡하다. 코틀린에서 자바로 자동 변환 기능을 사용했기 때문에...&amp;nbsp;&lt;/p&gt;
&lt;pre id=&quot;code_1683628827054&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;import android.app.Activity;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.ImageFormat;
import android.graphics.Matrix;
import android.graphics.RectF;
import android.graphics.SurfaceTexture;
import android.hardware.camera2.*;
import android.hardware.camera2.params.StreamConfigurationMap;
import android.media.Image;
import android.media.ImageReader;
import android.media.MediaRecorder;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.HandlerThread;
import android.util.Log;
import android.util.Size;
import android.util.SparseIntArray;
import android.view.LayoutInflater;
import android.view.Surface;
import android.view.TextureView;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.databinding.DataBindingUtil;
import androidx.fragment.app.Fragment;
import androidx.navigation.NavController;
import androidx.navigation.Navigation;

import java.io.File;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;

import io.reactivex.disposables.CompositeDisposable;
import kotlin.Metadata;
import kotlin.jvm.internal.Intrinsics;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import com.example.signalussample1_java.databinding.FragmentCameraBinding;
import com.gun0912.tedpermission.PermissionListener;
import com.gun0912.tedpermission.normal.TedPermission;

@Metadata(
        mv = {1, 7, 1},
        k = 1,
        d1 = {&quot;\u0000B\n\u0002\u0018\u0002\n\u0002\u0018\u0002\n\u0002\u0018\u0002\n\u0002\b\u0002\n\u0002\u0010\u000e\n\u0002\b\u0005\n\u0002\u0018\u0002\n\u0002\b\u0005\n\u0002\u0010\u0002\n\u0000\n\u0002\u0018\u0002\n\u0002\b\u0002\n\u0002\u0018\u0002\n\u0000\n\u0002\u0018\u0002\n\u0000\n\u0002\u0018\u0002\n\u0002\b\u0003\u0018\u00002\u00020\u00012\u00020\u0002B\u0005&amp;cent;\u0006\u0002\u0010\u0003J\u0012\u0010\u0010\u001a\u00020\u00112\b\u0010\u0012\u001a\u0004\u0018\u00010\u0013H\u0016J&amp;amp;\u0010\u0014\u001a\u0004\u0018\u00010\u00132\u0006\u0010\u0015\u001a\u00020\u00162\b\u0010\u0017\u001a\u0004\u0018\u00010\u00182\b\u0010\u0019\u001a\u0004\u0018\u00010\u001aH\u0016J\u001a\u0010\u001b\u001a\u00020\u00112\u0006\u0010\u001c\u001a\u00020\u00132\b\u0010\u0019\u001a\u0004\u0018\u00010\u001aH\u0016R\u001a\u0010\u0004\u001a\u00020\u0005X\u0086\u000e&amp;cent;\u0006\u000e\n\u0000\u001a\u0004\b\u0006\u0010\u0007\&quot;\u0004\b\b\u0010\tR\u001a\u0010\n\u001a\u00020\u000bX\u0086.&amp;cent;\u0006\u000e\n\u0000\u001a\u0004\b\f\u0010\r\&quot;\u0004\b\u000e\u0010\u000f&amp;uml;\u0006\u001d&quot;},
        d2 = {&quot;Lcom/example/signalussample1/fragment/cameraFragment;&quot;, &quot;Landroidx/fragment/app/Fragment;&quot;, &quot;Landroid/view/View$OnClickListener;&quot;, &quot;()V&quot;, &quot;body_part&quot;, &quot;&quot;, &quot;getBody_part&quot;, &quot;()Ljava/lang/String;&quot;, &quot;setBody_part&quot;, &quot;(Ljava/lang/String;)V&quot;, &quot;navController&quot;, &quot;Landroidx/navigation/NavController;&quot;, &quot;getNavController&quot;, &quot;()Landroidx/navigation/NavController;&quot;, &quot;setNavController&quot;, &quot;(Landroidx/navigation/NavController;)V&quot;, &quot;onClick&quot;, &quot;&quot;, &quot;v&quot;, &quot;Landroid/view/View;&quot;, &quot;onCreateView&quot;, &quot;inflater&quot;, &quot;Landroid/view/LayoutInflater;&quot;, &quot;container&quot;, &quot;Landroid/view/ViewGroup;&quot;, &quot;savedInstanceState&quot;, &quot;Landroid/os/Bundle;&quot;, &quot;onViewCreated&quot;, &quot;view&quot;, &quot;app_debug&quot;}
)
public final class cameraFragment extends Fragment implements View.OnClickListener  {
    @NotNull
    private String body_part = &quot;&quot;;
    public NavController navController;
    private HashMap _$_findViewCache;
    private static final String TAG = &quot;VideoFragment&quot;;

    FragmentCameraBinding binding;

    // 카메라 광각, 전면, 후면
    private static final String CAM_WHAT = &quot;2&quot;;
    private static final String CAM_FRONT = &quot;1&quot;;
    private static final String CAM_REAR = &quot;0&quot;;

    private String mCamId;

    CameraCaptureSession mCameraCaptureSession;
    CameraDevice mCameraDevice;
    CameraManager mCameraManager;

    Size mVideoSize;
    Size mPreviewSize;
    CaptureRequest.Builder mCaptureRequestBuilder;

    int mSensorOrientation;

    Semaphore mSemaphore = new Semaphore(1);

    HandlerThread mBackgroundThread;
    Handler mBackgroundHandler;

    MediaRecorder mMediaRecorder;

    private boolean mIsRecordingVideo;
    //public Handler handler;
    public static cameraFragment newInstance() {
        return new cameraFragment();
    }

    @NotNull
    public final NavController getNavController() {
        NavController var10000 = this.navController;
        if (var10000 == null) {
            Intrinsics.throwUninitializedPropertyAccessException(&quot;navController&quot;);
        }

        return var10000;
    }

    public final void setNavController(@NotNull NavController var1) {
        Intrinsics.checkNotNullParameter(var1, &quot;&amp;lt;set-?&amp;gt;&quot;);
        this.navController = var1;
    }

    @Nullable
    public View onCreateView(@NotNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        TedPermission.create()
                .setPermissionListener(permission)
                .setRationaleMessage(&quot;녹화를 위하여 권한을 허용해주세요.&quot;)
                .setDeniedMessage(&quot;권한이 거부되었습니다. 설정 &amp;gt; 권한에서 허용해주세요.&quot;)
                .setPermissions(android.Manifest.permission.CAMERA, android.Manifest.permission.WRITE_EXTERNAL_STORAGE, android.Manifest.permission.RECORD_AUDIO)
                .check();

        binding = DataBindingUtil.inflate(inflater, R.layout.fragment_camera, container, false);
        mCamId = CAM_FRONT;
        mCompositeDisposable = new CompositeDisposable();


        return binding.getRoot();
    }

    public void onViewCreated(@NotNull View view, @Nullable Bundle savedInstanceState) {
        Intrinsics.checkNotNullParameter(view, &quot;view&quot;);
        super.onViewCreated(view, savedInstanceState);


        this.navController = Navigation.findNavController(view);
        TextView var10000 = (TextView)this._$_findCachedViewById(id.translated);
        ((ImageView)this._$_findCachedViewById(id.imageView12)).setOnClickListener((View.OnClickListener)this);

        startCaptureImg();

    }

    public void onClick(@Nullable View v) {

        Integer var2 = v != null ? v.getId() : null;
        var3 = id.imageView12;
        if(var2!=null){
            if(var2==var3){
                startCaptureImg();

            }
        }   

    }


    public View _$_findCachedViewById(int var1) {
        if (this._$_findViewCache == null) {
            this._$_findViewCache = new HashMap();
        }

        View var2 = (View)this._$_findViewCache.get(var1);
        if (var2 == null) {
            View var10000 = this.getView();
            if (var10000 == null) {
                return null;
            }

            var2 = var10000.findViewById(var1);
            this._$_findViewCache.put(var1, var2);
        }

        return var2;
    }

    public void _$_clearFindViewByIdCache() {
        if (this._$_findViewCache != null) {
            this._$_findViewCache.clear();
        }

    }
    PermissionListener permission = new PermissionListener() {
        @Override
        public void onPermissionGranted() {
            Toast.makeText(getContext(), &quot;권한 허가&quot;, Toast.LENGTH_SHORT).show();

        }

        @Override
        public void onPermissionDenied(List&amp;lt;String&amp;gt; deniedPermissions) {
            Toast.makeText(getContext(), &quot;권한 거부&quot;, Toast.LENGTH_SHORT).show();

        }
    };

    public void onActivityCreated(@androidx.annotation.Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        assert getActivity() != null;
    }

    @Override
    public void onResume() {
        super.onResume();

        startBackgroundThread();
        if (binding.preview.isAvailable()) {
            openCamera(binding.preview.getWidth(), binding.preview.getHeight());
        } else {
            binding.preview.setSurfaceTextureListener(mSurfaceTextureListener);
        }
    }


    private TextureView.SurfaceTextureListener mSurfaceTextureListener = new TextureView.SurfaceTextureListener() {
        @Override
        public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
            openCamera(binding.preview.getWidth(), binding.preview.getHeight());
        }

        @Override
        public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
            if(!mIsRecordingVideo) configureTransform(width, height);
        }

        @Override
        public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
            return true;
        }

        @Override
        public void onSurfaceTextureUpdated(SurfaceTexture surface) {

        }
    };

    private CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {
        @Override
        public void onOpened(@NonNull CameraDevice camera) {
            mCameraDevice = camera;
            startPreview();
            mSemaphore.release();
            if (null != binding.preview) {
                configureTransform(binding.preview.getWidth(), binding.preview.getHeight());
            }

        }

        @Override
        public void onDisconnected(@NonNull CameraDevice camera) {
            mSemaphore.release();
            camera.close();
            mCameraDevice = null;
        }

        @Override
        public void onError(@NonNull CameraDevice camera, int error) {
            mSemaphore.release();
            camera.close();
            mCameraDevice = null;
            Activity activity = getActivity();
            assert activity != null;
            activity.finish();
        }
    };


    //카메라 기능 호출
    private void openCamera(int width, int height) {
        Activity activity = getActivity();
        assert activity != null;
        mCameraManager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE);
        try {
            if (!mSemaphore.tryAcquire(2500, TimeUnit.MILLISECONDS)) {
                throw new RuntimeException(&quot;Time out waiting to lock camera opening.&quot;);
            }
            CameraCharacteristics cc = mCameraManager.getCameraCharacteristics(mCamId);
            StreamConfigurationMap scm = cc.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
            mSensorOrientation = cc.get(CameraCharacteristics.SENSOR_ORIENTATION);
            if (scm == null) {
                throw new RuntimeException(&quot;Cannot get available preview/video sizes&quot;);
            }

            mVideoSize = chooseVideoSize(scm.getOutputSizes(MediaRecorder.class));
            mPreviewSize = chooseOptimalSize(scm.getOutputSizes(SurfaceTexture.class), width, height, mVideoSize);

            int orientation = getResources().getConfiguration().orientation;
            if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
                binding.preview.setAspectRatio(mPreviewSize.getWidth(), mPreviewSize.getHeight());
            } else {
                binding.preview.setAspectRatio(mPreviewSize.getHeight(), mPreviewSize.getWidth());
            }

            configureTransform(width, height);
            mMediaRecorder = new MediaRecorder();
            mCameraManager.openCamera(mCamId, mStateCallback, mBackgroundHandler);
        } catch (CameraAccessException | SecurityException | NullPointerException | InterruptedException e) {
            e.printStackTrace();
            activity.finish();
        }


    }

    private static Size chooseVideoSize(Size[] choices) {
        for (Size size : choices) {
            // 해상도에 맞게 설정
            if(size.getWidth() == size.getHeight() * 4 / 3 &amp;amp;&amp;amp; size.getWidth() &amp;lt;= 1080){
                return size;
            }
        }
        return choices[choices.length - 1];
    }

    private static Size chooseOptimalSize(Size[] choices, int width, int height, Size aspectRatio) {
        List&amp;lt;Size&amp;gt; bigEnough = new ArrayList&amp;lt;&amp;gt;();
        int w = aspectRatio.getWidth();
        int h = aspectRatio.getHeight();
        for (Size ops : choices) {
            if(ops.getHeight() == ops.getWidth() * h / w &amp;amp;&amp;amp; ops.getWidth() &amp;gt;= width &amp;amp;&amp;amp; ops.getHeight() &amp;gt;= height) {
                bigEnough.add(ops);
            }
        }

        if (bigEnough.size() &amp;gt; 0) {
            return Collections.min(bigEnough, new CompareSizesByArea());
        } else {
            return choices[0];
        }
    }


    // 카메라 닫기
    private void closeCamera() {
        try {
            mSemaphore.acquire();
            closePreviewSession();
            if (null != mCameraDevice) {
                mCameraDevice.close();
                mCameraDevice = null;
            }
            if (null != mMediaRecorder) {
                mMediaRecorder.release();
                mMediaRecorder = null;
            }
        } catch (InterruptedException ie) {
            ie.printStackTrace();
        } finally {
            mSemaphore.release();
        }
    }

    //미리보기 기능
    private void startPreview() {
        if(null == mCameraDevice || !binding.preview.isAvailable() || null == mPreviewSize) {
            Toast.makeText(getContext(), &quot;CameraDeviceIsNotAvailable&quot;, Toast.LENGTH_SHORT).show();
            return;
        }

        try {
            closePreviewSession();
            SurfaceTexture texture = binding.preview.getSurfaceTexture();
            assert texture != null;
            texture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
            mCaptureRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);

            Surface previewSurface = new Surface(texture);
            mCaptureRequestBuilder.addTarget(previewSurface);
            mCameraDevice.createCaptureSession(Collections.singletonList(previewSurface), new CameraCaptureSession.StateCallback() {
                @Override
                public void onConfigured(@NonNull CameraCaptureSession session) {
                    mCameraCaptureSession = session;
                    updatePreview();
                }

                @Override
                public void onConfigureFailed(@NonNull CameraCaptureSession session) {
                    Activity activity = getActivity();
                    assert activity != null;
                    Toast.makeText(activity, &quot;Failed&quot;, Toast.LENGTH_SHORT).show();
                }
            }, mBackgroundHandler);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }

    }

    private void updatePreview() {
        if (null == mCameraDevice) {
            return;
        }
        try {
            setUpCaptureRequestBuilder(mCaptureRequestBuilder);
            HandlerThread thread = new HandlerThread(&quot;CameraPreview&quot;);
            thread.start();
            mCameraCaptureSession.setRepeatingRequest(mCaptureRequestBuilder.build(), null, mBackgroundHandler);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }

    private void setUpCaptureRequestBuilder(CaptureRequest.Builder builder) {
        builder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);
    }


    private void configureTransform(int viewWidth, int viewHeight) {
        Activity activity = getActivity();
        if (null == binding.preview || null == mPreviewSize || null == activity) {
            return;
        }
        int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
        Matrix matrix = new Matrix();
        RectF viewRect = new RectF(0, 0, viewWidth, viewHeight);
        RectF bufferRect = new RectF(0, 0, mPreviewSize.getWidth(), mPreviewSize.getHeight());

        float centerX = viewRect.centerX();
        float centerY = viewRect.centerY();

        if (Surface.ROTATION_90 == rotation || Surface.ROTATION_270 == rotation) {
            bufferRect.offset(centerX - bufferRect.centerX(), centerY - bufferRect.centerY());
            matrix.setRectToRect(viewRect, bufferRect, Matrix.ScaleToFit.FILL);
            float scale = Math.max(
                    (float) viewHeight / mPreviewSize.getHeight(),
                    (float) viewWidth / mPreviewSize.getWidth()
            );
            matrix.postScale(scale, scale, centerX, centerY);
            matrix.postRotate(90 * (rotation - 2), centerX, centerY);
        }
        activity.runOnUiThread(() -&amp;gt; binding.preview.setTransform(matrix));
    }

    private void startBackgroundThread() {
        mBackgroundThread = new HandlerThread(&quot;CameraBackground&quot;);
        mBackgroundThread.start();
        mBackgroundHandler = new Handler(mBackgroundThread.getLooper());
    }

    private void stopBackgroundThread() {
        mBackgroundThread.quitSafely();
        try {
            mBackgroundThread.join();
            mBackgroundThread = null;
            mBackgroundHandler = null;
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void closePreviewSession() {
        if (mCameraCaptureSession != null) {
            mCameraCaptureSession.close();
            mCameraCaptureSession = null;
        }
    }

    private static final int SENSOR_ORIENTATION_DEFAULT_DEGREES = 90;
    private static final int SENSOR_ORIENTATION_INVERSE_DEGREES = 270;
    private static final SparseIntArray DEFAULT_ORIENTATIONS = new SparseIntArray();
    private static final SparseIntArray INVERSE_ORIENTATIONS = new SparseIntArray();
    static {
        DEFAULT_ORIENTATIONS.append(Surface.ROTATION_0, 90);
        DEFAULT_ORIENTATIONS.append(Surface.ROTATION_90, 0);
        DEFAULT_ORIENTATIONS.append(Surface.ROTATION_180, 270);
        DEFAULT_ORIENTATIONS.append(Surface.ROTATION_270, 180);
    }

    static {
        INVERSE_ORIENTATIONS.append(Surface.ROTATION_0, 270);
        INVERSE_ORIENTATIONS.append(Surface.ROTATION_90, 180);
        INVERSE_ORIENTATIONS.append(Surface.ROTATION_180, 90);
        INVERSE_ORIENTATIONS.append(Surface.ROTATION_270, 0);
    }


    //캡처와 전송시작
    private void startCaptureImg() {
        if (null == mCameraDevice || !binding.preview.isAvailable() || null == mPreviewSize) {//카메라가 사용할 수 있는 상태인지 확인
            Log.e(TAG, &quot;mCameraDevice is null, return&quot;);
            return;
        }
        Toast.makeText(getContext(), &quot;이미지가져오기 실행&quot;, Toast.LENGTH_SHORT).show();

        assert getActivity() != null;//activity와 fragment가 잘 attach되어있고, 아직 destroy되지 않았다는 뜻
        SurfaceTexture texture = binding.preview.getSurfaceTexture();//Preview texture과 관련된 surfacetexture를 찾는다.

        assert texture !=null;//Preview texture를 사용할 수 있는 지 확인
        try {
            int width = 640;
            int height = 480;

            assert texture != null;
            ImageReader reader = ImageReader.newInstance(width, height, ImageFormat.JPEG, 1);//JPEG 형식으로 캡처된 이미지를 수신할 ImageReader 인스턴스 생성
            List&amp;lt;Surface&amp;gt; outputSurfaces = new ArrayList&amp;lt;Surface&amp;gt;(2);
            outputSurfaces.add(reader.getSurface());
            outputSurfaces.add(new Surface(texture));


            final CaptureRequest.Builder captureBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
            captureBuilder.addTarget(reader.getSurface());
            captureBuilder.set(CaptureRequest.CONTROL_MODE, CameraMetadata.CONTROL_MODE_AUTO);//카메라실행을 위한 세팅. 카메라 캡처 요청에 대한 제어 모드를 자동으로 설정한다.


            ImageReader.OnImageAvailableListener readerListener = new ImageReader.OnImageAvailableListener() {//이미지를 사용할 수 있을 때 트리거되는 OnImageAvailableListener를 만든다.
                @Override
                public void onImageAvailable(ImageReader reader) {//readerListender 내부에서 캡처된 이미지를 획득
                    Image image = null;
                    try {
                        image = reader.acquireLatestImage();
                        ByteBuffer buffer = image.getPlanes()[0].getBuffer();
                        byte[] bytes = new byte[buffer.remaining()];
                        buffer.get(bytes);
                        Toast.makeText(getContext(), &quot;바이트 데이터 얻기 성공&quot;, Toast.LENGTH_SHORT).show();

                        sendImageToServer(bytes); // Call your method to send the byte data to the server
                    } finally {
                        if (image != null) {
                            image.close();
                        }
                    }
                }
            };

            HandlerThread thread = new HandlerThread(&quot;CameraPicture&quot;);
            thread.start();
            final Handler backgroudHandler = new Handler(thread.getLooper());
            reader.setOnImageAvailableListener(readerListener, backgroudHandler);

            final CameraCaptureSession.CaptureCallback captureListener = new CameraCaptureSession.CaptureCallback() {
                @Override
                public void onCaptureCompleted(CameraCaptureSession session,//캡처 완료 시 서버로 전송
                                               CaptureRequest request, TotalCaptureResult result) {
                    super.onCaptureCompleted(session, request, result);
                    startPreview();
                }

            };

            mCameraDevice.createCaptureSession(outputSurfaces, new CameraCaptureSession.StateCallback() {
                @Override
                public void onConfigured(CameraCaptureSession session) {
                    try {
                        session.capture(captureBuilder.build(), captureListener, mBackgroundHandler);
                    } catch (CameraAccessException e) {
                        e.printStackTrace();

                    }
                }

                @Override
                public void onConfigureFailed(CameraCaptureSession session) {

                }
            }, mBackgroundHandler);



        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }
    private void sendImageToServer(byte[] imageData) {
        // Implement your networking code here to send the byte data to the server
        // This can involve using libraries such as HttpURLConnection, OkHttp, Retrofit, etc.
        // Construct an HTTP request, set headers and parameters, and attach the byte data
        // to the request body before sending it to the server.
        Toast.makeText(getContext(), &quot;서버로 이미지 전송 시도&quot;, Toast.LENGTH_SHORT).show();
    }

    static class CompareSizesByArea implements Comparator&amp;lt;Size&amp;gt; {
        @Override
        public int compare(Size lhs, Size rhs) {
            return Long.signum((long) lhs.getWidth() * lhs.getHeight() - (long) rhs.getWidth() * rhs.getHeight());
        }
    }

    CompositeDisposable mCompositeDisposable;

    // $FF: synthetic method
    public void onDestroyView() {
        stopBackgroundThread();
        super.onDestroyView();
        this._$_clearFindViewByIdCache();
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;참고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;카메라 이미지&amp;nbsp; 추출에 사용 링크 내 2번.&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a href=&quot;https://hw00173.tistory.com/15&quot;&gt;https://hw00173.tistory.com/15&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1683629268280&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;[안드로이드 링크 정리] Camera2 API를 이용한 사진찍기 기능 관련 링크 [2019_12_01 - 2019_12_08]&quot; data-og-description=&quot;해당 작성 링크들은 개발하면서 참고 했던 링크들을 주제별로 정리한 자료입니다. 대부분 링크에 대한 설명이므로, 해당 기능에 대한 설명이 부족할 수 있습니다. ! 1. Camrea2 API를 이용한 카메라 &quot; data-og-host=&quot;hw00173.tistory.com&quot; data-og-source-url=&quot;https://hw00173.tistory.com/15&quot; data-og-url=&quot;https://hw00173.tistory.com/15&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/qjftp/hySyj0irhP/a7220qmmsJOsrl5V6HzmV0/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/ch40M6/hySyfp330S/GepYw4no5EdaQSXkzvKRnk/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800&quot;&gt;&lt;a href=&quot;https://hw00173.tistory.com/15&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://hw00173.tistory.com/15&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/qjftp/hySyj0irhP/a7220qmmsJOsrl5V6HzmV0/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/ch40M6/hySyfp330S/GepYw4no5EdaQSXkzvKRnk/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;[안드로이드 링크 정리] Camera2 API를 이용한 사진찍기 기능 관련 링크 [2019_12_01 - 2019_12_08]&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;해당 작성 링크들은 개발하면서 참고 했던 링크들을 주제별로 정리한 자료입니다. 대부분 링크에 대한 설명이므로, 해당 기능에 대한 설명이 부족할 수 있습니다. ! 1. Camrea2 API를 이용한 카메라&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;hw00173.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;카메라 Preview 띄우는 데 이용&lt;/p&gt;
&lt;p style=&quot;background-color: #ffffff; color: #555555; text-align: start;&quot; data-ke-size=&quot;size16&quot;&gt;&lt;a style=&quot;color: #6bacce;&quot; href=&quot;https://altongmon.tistory.com/809&quot;&gt;안드로이드 Camera2 api 로 동영상 촬영하고 갤러리에 저장하기. (tistory.com)&lt;/a&gt;&lt;/p&gt;
&lt;figure id=&quot;og_1683629282151&quot; contenteditable=&quot;false&quot; data-ke-type=&quot;opengraph&quot; data-ke-align=&quot;alignCenter&quot; data-og-type=&quot;article&quot; data-og-title=&quot;안드로이드 Camera2 api 로 동영상 촬영하고 갤러리에 저장하기.&quot; data-og-description=&quot;공감 및 댓글, 광고클릭은 포스팅 하는데 아주아주 큰 힘이 됩니다!!포스팅 내용이 찾아주신 분들께 도움이 되길 바라며더 깔끔하고 좋은 포스팅을 만들어 나가겠습니다^^ 이번 포스팅에서는 안&quot; data-og-host=&quot;altongmon.tistory.com&quot; data-og-source-url=&quot;https://altongmon.tistory.com/809&quot; data-og-url=&quot;https://altongmon.tistory.com/809&quot; data-og-image=&quot;https://scrap.kakaocdn.net/dn/dh2q3H/hySyrYmDkT/fsKWSxVBN173KU3GivGcp0/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/bSB5AJ/hySysQt2o5/KKlaLF5TAcSkrGD2hB11p1/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/cB1FfQ/hySyf4FvU8/8bzZK29h7ki42QjHa6pTkK/img.png?width=1347&amp;amp;height=1306&amp;amp;face=0_0_1347_1306&quot;&gt;&lt;a href=&quot;https://altongmon.tistory.com/809&quot; target=&quot;_blank&quot; rel=&quot;noopener&quot; data-source-url=&quot;https://altongmon.tistory.com/809&quot;&gt;
&lt;div class=&quot;og-image&quot; style=&quot;background-image: url('https://scrap.kakaocdn.net/dn/dh2q3H/hySyrYmDkT/fsKWSxVBN173KU3GivGcp0/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/bSB5AJ/hySysQt2o5/KKlaLF5TAcSkrGD2hB11p1/img.png?width=800&amp;amp;height=800&amp;amp;face=0_0_800_800,https://scrap.kakaocdn.net/dn/cB1FfQ/hySyf4FvU8/8bzZK29h7ki42QjHa6pTkK/img.png?width=1347&amp;amp;height=1306&amp;amp;face=0_0_1347_1306');&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;og-text&quot;&gt;
&lt;p class=&quot;og-title&quot; data-ke-size=&quot;size16&quot;&gt;안드로이드 Camera2 api 로 동영상 촬영하고 갤러리에 저장하기.&lt;/p&gt;
&lt;p class=&quot;og-desc&quot; data-ke-size=&quot;size16&quot;&gt;공감 및 댓글, 광고클릭은 포스팅 하는데 아주아주 큰 힘이 됩니다!!포스팅 내용이 찾아주신 분들께 도움이 되길 바라며더 깔끔하고 좋은 포스팅을 만들어 나가겠습니다^^ 이번 포스팅에서는 안&lt;/p&gt;
&lt;p class=&quot;og-host&quot; data-ke-size=&quot;size16&quot;&gt;altongmon.tistory.com&lt;/p&gt;
&lt;/div&gt;
&lt;/a&gt;&lt;/figure&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;</description>
      <category>프로젝트/안드로이드스튜디오</category>
      <author>코오오 코오</author>
      <guid isPermaLink="true">https://fightingway.tistory.com/33</guid>
      <comments>https://fightingway.tistory.com/33#entry33comment</comments>
      <pubDate>Tue, 9 May 2023 19:48:06 +0900</pubDate>
    </item>
    <item>
      <title>서버에 이미지를 보낼 때, 파일? 바이트 코드?</title>
      <link>https://fightingway.tistory.com/32</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;이미지를 서버로 보낼 때 이미지 데이터를 전송하기 위한 여러 옵션이 있습니다. 이미지를 저장된 파일로 보내거나 획득한 바이트 데이터를 직접 보낼 수 있습니다. 두 접근 방식 모두 장점과 고려 사항이 있습니다.&lt;span style=&quot;background-color: #f7f7f8; color: #374151; text-align: start;&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ol style=&quot;list-style-type: decimal; background-color: #f7f7f8; color: #374151; text-align: start;&quot; data-ke-list-type=&quot;decimal&quot;&gt;
&lt;li&gt;저장 파일로 보내기:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이 방법에서는 캡처한 이미지를 장치의 저장소에 파일로 저장한 다음 파일을 서버로 보냅니다.&lt;/li&gt;
&lt;li&gt;장점:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;파일을 보내면 전체 바이트 데이터를 메모리에서 관리할 필요 없이 큰 이미지 크기를 쉽게 처리할 수 있습니다.&lt;/li&gt;
&lt;li&gt;다른 파일 업로드와 마찬가지로 서버에서 이미지 파일을 처리하고 처리할 수 있습니다.&lt;/li&gt;
&lt;li&gt;파일을 서버로 보낼 때 파일과 함께 메타데이터 및 추가 정보를 추가할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;고려 사항:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이미지를 파일로 저장하려면 기기의 저장 공간이 필요합니다.&lt;/li&gt;
&lt;li&gt;이미지 파일 저장 및 읽기에는 추가 디스크 I/O 작업이 포함됩니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;획득한 바이트 데이터 전송:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;이 방법은 캡처된 이미지에서 얻은 바이트 데이터를 파일로 저장하지 않고 직접 전송합니다.&lt;/li&gt;
&lt;li&gt;장점:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;바이트 데이터를 직접 전송하는 것은 이미지 데이터의 즉각적인 처리 또는 전송이 필요한 실시간 또는 스트리밍 시나리오를 처리할 때 유용할 수 있습니다.&lt;/li&gt;
&lt;li&gt;이미지를 디스크에 저장할 필요가 없으며 메모리를 더 효율적으로 사용할 수 있습니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;고려 사항:
&lt;ul style=&quot;list-style-type: disc;&quot; data-ke-list-type=&quot;disc&quot;&gt;
&lt;li&gt;바이트 데이터를 직접 보낼 때 서버의 허용된 요청 크기 제한 내에 맞아야 하므로 특히 큰 이미지의 경우 데이터 크기를 처리해야 합니다.&lt;/li&gt;
&lt;li&gt;요청의 일부로 전송하기 전에 바이트 데이터를 적절한 형식(예: Base64 인코딩)으로 변환해야 할 수 있습니다.&lt;/li&gt;
&lt;li&gt;서버는 바이트 데이터를 직접 수신하고 처리하기 위해 적절한 API 또는 엔드포인트를 가지고 있어야 합니다.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #374151; text-align: start;&quot;&gt;저장된 파일로 전송하거나 바이트 데이터를 직접 전송하는 것 중에서 선택하는 것은 서버의 기능 및 제약 조건, 이미지 크기, 네트워크 조건 및 원하는 처리 흐름과 같은 특정 요구 사항에 따라 다릅니다. 결정을 내릴 때 효율성, 확장성, 서버 측 처리 기능, 장치 및 네트워크 인프라의 한계와 같은 요소를 고려하십시오.&lt;/span&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;span style=&quot;background-color: #ffffff; color: #374151; text-align: start;&quot;&gt;Chat GPT가 알려줬다. 내가 기억하려고 작성함.&lt;/span&gt;&lt;/p&gt;</description>
      <category>프로젝트/안드로이드스튜디오</category>
      <author>코오오 코오</author>
      <guid isPermaLink="true">https://fightingway.tistory.com/32</guid>
      <comments>https://fightingway.tistory.com/32#entry32comment</comments>
      <pubDate>Tue, 9 May 2023 16:23:18 +0900</pubDate>
    </item>
    <item>
      <title>산업경영론</title>
      <link>https://fightingway.tistory.com/29</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;제 1장 빠르게 변화하는 비즈니스 환경에서의 리스크에 대한 대응과 수익창출&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;비즈니스와 부의 창출&lt;/li&gt;
&lt;li&gt;부의 창출에서 기업가의 중요성&lt;/li&gt;
&lt;li&gt;기업과 환경&lt;/li&gt;
&lt;li&gt;미국 기업의 변화과정&lt;/li&gt;
&lt;li&gt;[부의&amp;nbsp;창출에&amp;nbsp;기업가가&amp;nbsp;미치는&amp;nbsp;중요성] &lt;br /&gt;-생산의&amp;nbsp;5가지&amp;nbsp;요소 &lt;br /&gt;1.토지 &lt;br /&gt;2.노동 &lt;br /&gt;3.자본 &lt;br /&gt;4.기업가정신 &lt;br /&gt;5.지식 &lt;br /&gt;&lt;br /&gt;특히&amp;nbsp;자본이&amp;nbsp;압도적으로&amp;nbsp;중요하다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제 2장 경제학 이해하기&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;경제시스템이 기업에 영향을 미치는 방법&lt;/li&gt;
&lt;li&gt;자유시장 자본주의 이해&lt;/li&gt;
&lt;li&gt;사회주의 이해&lt;/li&gt;
&lt;li&gt;공산주의 이해&lt;/li&gt;
&lt;li&gt;혼합경제로의 추세&lt;/li&gt;
&lt;li&gt;[경제학&amp;nbsp;이해하기] &lt;br /&gt;-아담&amp;nbsp;스미스와&amp;nbsp;부의&amp;nbsp;창출 &lt;br /&gt;경제에&amp;nbsp;가장&amp;nbsp;중요한&amp;nbsp;요소는&amp;nbsp;자유이다.&amp;nbsp;토지&amp;nbsp;및&amp;nbsp;부동산을&amp;nbsp;소유할&amp;nbsp;수&amp;nbsp;있는&amp;nbsp;자유와,&amp;nbsp;기업&amp;nbsp;이익을&amp;nbsp;소유할&amp;nbsp;수&amp;nbsp;있는&amp;nbsp;권리는&amp;nbsp;필수적인&amp;nbsp;것이다.&amp;nbsp;노력에&amp;nbsp;대한&amp;nbsp;댓가가&amp;nbsp;확실히&amp;nbsp;보장될&amp;nbsp;때&amp;nbsp;사람들은&amp;nbsp;열심히&amp;nbsp;일할&amp;nbsp;것이다. &lt;br /&gt;-아담&amp;nbsp;스미스의&amp;nbsp;국부론&amp;nbsp;'보이지&amp;nbsp;않는&amp;nbsp;손'&amp;nbsp;:&amp;nbsp;자기&amp;nbsp;중심적인&amp;nbsp;이익을&amp;nbsp;다수를&amp;nbsp;위한&amp;nbsp;사회적&amp;nbsp;경제적&amp;nbsp;이익으로&amp;nbsp;전환하는&amp;nbsp;과정. &lt;br /&gt;사람들이&amp;nbsp;자신의&amp;nbsp;삶의&amp;nbsp;상황을&amp;nbsp;개선해&amp;nbsp;나가는&amp;nbsp;과정&amp;nbsp;속에서&amp;nbsp;제품이나&amp;nbsp;서비스,&amp;nbsp;또는&amp;nbsp;아이디어의&amp;nbsp;생산을&amp;nbsp;통해,&amp;nbsp;또는&amp;nbsp;자선&amp;nbsp;기부활동&amp;nbsp;등을&amp;nbsp;통해&amp;nbsp;경제&amp;nbsp;전체가&amp;nbsp;번영하는&amp;nbsp;데&amp;nbsp;도움을&amp;nbsp;주고&amp;nbsp;있음. &lt;br /&gt;-이것이&amp;nbsp;적용된&amp;nbsp;사례 &lt;br /&gt;기업&amp;nbsp;소유주가&amp;nbsp;자신의&amp;nbsp;노력에&amp;nbsp;대한&amp;nbsp;보상을&amp;nbsp;'소유'하고&amp;nbsp;'지킬&amp;nbsp;수&amp;nbsp;있다'고&amp;nbsp;믿을&amp;nbsp;때&amp;nbsp;열심히&amp;nbsp;일하도록&amp;nbsp;동기부여된다고&amp;nbsp;한다. &lt;br /&gt;ex)식당이&amp;nbsp;번창할&amp;nbsp;때&amp;nbsp;종업원을&amp;nbsp;더&amp;nbsp;채용하고,&amp;nbsp;가게가&amp;nbsp;성장한다.&amp;nbsp;-&amp;gt;간접적으로&amp;nbsp;사회와&amp;nbsp;국가&amp;nbsp;경제에&amp;nbsp;기여한다. &lt;br /&gt;&lt;br /&gt;-자유시장&amp;nbsp;자본주의의&amp;nbsp;4가지&amp;nbsp;기본권리 &lt;br /&gt;1.사유재산권&amp;nbsp;-&amp;gt;재산을&amp;nbsp;사유할&amp;nbsp;수&amp;nbsp;있다는&amp;nbsp;자본주의적&amp;nbsp;사실이&amp;nbsp;자본을&amp;nbsp;모으려는&amp;nbsp;노력을&amp;nbsp;부추긴다. &lt;br /&gt;2.기업을&amp;nbsp;소유할&amp;nbsp;수&amp;nbsp;있는&amp;nbsp;권리,&amp;nbsp;이익을&amp;nbsp;모두&amp;nbsp;가질&amp;nbsp;수&amp;nbsp;있는&amp;nbsp;권리&amp;nbsp;-&amp;gt;노력에&amp;nbsp;대한&amp;nbsp;보상이&amp;nbsp;올곧게&amp;nbsp;돌아온다는&amp;nbsp;점이&amp;nbsp;열심히&amp;nbsp;일하도록&amp;nbsp;동기부여된다. &lt;br /&gt;3.경쟁의&amp;nbsp;자유&amp;nbsp;-&amp;gt;다른&amp;nbsp;기업과&amp;nbsp;경쟁함으로서&amp;nbsp;더&amp;nbsp;나은&amp;nbsp;기업을&amp;nbsp;만들겠다는&amp;nbsp;동기부여된다. &lt;br /&gt;4.선택의&amp;nbsp;자유&amp;nbsp;-&amp;gt;고객&amp;nbsp;입장에서&amp;nbsp;어떤&amp;nbsp;기업이든&amp;nbsp;선택할&amp;nbsp;수&amp;nbsp;있다는&amp;nbsp;점이&amp;nbsp;동기부여된다. &lt;br /&gt;&lt;br /&gt;-자유시장의&amp;nbsp;작동원리 &lt;br /&gt;무엇을,&amp;nbsp;얼마만큼&amp;nbsp;생산할&amp;nbsp;것인지가&amp;nbsp;시장에&amp;nbsp;의해&amp;nbsp;결정된다. &lt;br /&gt;소비자들은&amp;nbsp;무엇을&amp;nbsp;선호하고&amp;nbsp;얼마만큼&amp;nbsp;좋아하는지에&amp;nbsp;대한&amp;nbsp;신호를&amp;nbsp;보낸다. &lt;br /&gt;가격은&amp;nbsp;기업에게&amp;nbsp;한&amp;nbsp;제품을&amp;nbsp;얼마만큼&amp;nbsp;생산할&amp;nbsp;것인지&amp;nbsp;알려준다. &lt;br /&gt;어떤&amp;nbsp;상품이&amp;nbsp;필요하지만&amp;nbsp;구하기&amp;nbsp;어렵다면&amp;nbsp;더&amp;nbsp;많은&amp;nbsp;상품이&amp;nbsp;나오기&amp;nbsp;전까지&amp;nbsp;가격은&amp;nbsp;계속해서&amp;nbsp;상승하게&amp;nbsp;된다. &lt;br /&gt;-가격결정. &lt;br /&gt;수요,&amp;nbsp;공급,&amp;nbsp;시장가격.&amp;nbsp;공급곡선은&amp;nbsp;우상향곡선&amp;nbsp;수요곡선은&amp;nbsp;우하향곡선.&amp;nbsp;두&amp;nbsp;곡선이&amp;nbsp;만나는&amp;nbsp;균형점이&amp;nbsp;가격을&amp;nbsp;결정한다. &lt;br /&gt;-자유경제시스템.&amp;nbsp;인플레이션과&amp;nbsp;가격지수 &lt;br /&gt;인플레이션&amp;nbsp;:&amp;nbsp;시간이&amp;nbsp;지남에&amp;nbsp;따라&amp;nbsp;제품과&amp;nbsp;서비스의&amp;nbsp;가격이&amp;nbsp;전반적으로&amp;nbsp;상승하는&amp;nbsp;현상.&amp;nbsp;화폐가치&amp;nbsp;하락,&amp;nbsp;상품가치&amp;nbsp;상승.&amp;nbsp; &lt;br /&gt;디스인플레이션&amp;nbsp;:&amp;nbsp;가격상승이&amp;nbsp;느려지는&amp;nbsp;현상 &lt;br /&gt;디플레이션&amp;nbsp;:&amp;nbsp;가격이&amp;nbsp;하락하는&amp;nbsp;현상 &lt;br /&gt;스태그플레이션&amp;nbsp;:&amp;nbsp;경기가&amp;nbsp;침체됨에도&amp;nbsp;불구하고&amp;nbsp;가격이&amp;nbsp;오르는&amp;nbsp;현상 &lt;br /&gt;&lt;br /&gt;-소비자물가지수(CPI)&amp;nbsp;:&amp;nbsp;인플레이션&amp;nbsp;혹은&amp;nbsp;디플레이션의&amp;nbsp;정도를&amp;nbsp;매달&amp;nbsp;측정하는&amp;nbsp;통계수치 &lt;br /&gt;-핵심&amp;nbsp;인플레이션&amp;nbsp;:&amp;nbsp;소비자물가지수에서&amp;nbsp;식품과&amp;nbsp;에너지비용을&amp;nbsp;차감한것 &lt;br /&gt;-생산자&amp;nbsp;물가지수&amp;nbsp;:&amp;nbsp;도매물가의&amp;nbsp;변동을&amp;nbsp;측정한&amp;nbsp;지수 &lt;br /&gt;&lt;br /&gt;&lt;br /&gt;-케인즈&amp;nbsp;학파의&amp;nbsp;경제이론&amp;nbsp;:&amp;nbsp;정부지출을&amp;nbsp;늘리고&amp;nbsp;세금을&amp;nbsp;줄이는&amp;nbsp;정책은&amp;nbsp;경기침체기에&amp;nbsp;경기를&amp;nbsp;부양시킬&amp;nbsp;수&amp;nbsp;있다.&amp;nbsp;저서인&amp;nbsp;&amp;lt;고용,이자&amp;nbsp;및&amp;nbsp;화폐의&amp;nbsp;일반이론&amp;gt;에서&amp;nbsp;완전고용을&amp;nbsp;실현,&amp;nbsp;유지하기&amp;nbsp;위해서는&amp;nbsp;자유방임주의가&amp;nbsp;아닌&amp;nbsp;정부의&amp;nbsp;보완책(공공지출)이&amp;nbsp;필요하다고&amp;nbsp;주장하였다&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제 3장 글로벌 시장에서의 비즈니스&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;다이나믹한 글로벌 시장&lt;/li&gt;
&lt;li&gt;왜 다른 나라와 무역을 하는가?&lt;/li&gt;
&lt;li&gt;글로벌 무역에 동참하기&lt;/li&gt;
&lt;li&gt;글로벌 시장에 진출하기 위한 전략&lt;/li&gt;
&lt;li&gt;글로벌 무역에 영향을 미치는 요인들&lt;/li&gt;
&lt;li&gt;보호무역주의&lt;/li&gt;
&lt;li&gt;글로벌 무역의 미래&lt;/li&gt;
&lt;li&gt;왜&amp;nbsp;다른&amp;nbsp;국가와&amp;nbsp;무역을&amp;nbsp;하는가? &lt;br /&gt;가장&amp;nbsp;잘&amp;nbsp;생산할&amp;nbsp;수&amp;nbsp;있는&amp;nbsp;것을&amp;nbsp;생산하고,&amp;nbsp;다른&amp;nbsp;필요한&amp;nbsp;것을&amp;nbsp;살&amp;nbsp;수&amp;nbsp;있도록&amp;nbsp;해준다. &lt;br /&gt;-자유무역 &lt;br /&gt;-비교우위론과&amp;nbsp;절대우위론 &lt;br /&gt;비교우위론&amp;nbsp;:&amp;nbsp;한&amp;nbsp;국가는&amp;nbsp;자신이&amp;nbsp;가장&amp;nbsp;효율적으로&amp;nbsp;생산하는&amp;nbsp;생산품을&amp;nbsp;다른&amp;nbsp;나라에&amp;nbsp;팔고,&amp;nbsp;다른&amp;nbsp;나라로부터는&amp;nbsp;자신이&amp;nbsp;그만큼&amp;nbsp;효율적으로&amp;nbsp;생산할&amp;nbsp;수&amp;nbsp;없는&amp;nbsp;상품을&amp;nbsp;사와야한다. &lt;br /&gt;절대우위론&amp;nbsp;:&amp;nbsp;한&amp;nbsp;국가가&amp;nbsp;특정&amp;nbsp;생산품에&amp;nbsp;대한&amp;nbsp;독점력을&amp;nbsp;가지고&amp;nbsp;있거나&amp;nbsp;다른&amp;nbsp;모든&amp;nbsp;나라보다&amp;nbsp;어떤&amp;nbsp;제품을&amp;nbsp;더&amp;nbsp;효율적으로&amp;nbsp;생산할&amp;nbsp;수&amp;nbsp;있어야&amp;nbsp;한다. &lt;br /&gt;-글로벌&amp;nbsp;시장&amp;nbsp;진출&amp;nbsp;전략 &lt;br /&gt;라이센싱&amp;nbsp;수출&amp;nbsp;프랜차이징&amp;nbsp;위탁제조&amp;nbsp;전략적&amp;nbsp;제휴&amp;nbsp;해외직접투자 &lt;br /&gt;--------관여도,&amp;nbsp;통제력,&amp;nbsp;위험,&amp;nbsp;잠재수익의&amp;nbsp;양--------&amp;gt; &lt;br /&gt;위탁제조,&amp;nbsp;OEM(주문자가&amp;nbsp;설계,&amp;nbsp;기술,&amp;nbsp;특허&amp;nbsp;소유.&amp;nbsp;생산만&amp;nbsp;해라.)&amp;nbsp;ODM(상표는&amp;nbsp;주문자,&amp;nbsp;개발은&amp;nbsp;제조자.&amp;nbsp;개발자&amp;nbsp;아이디어&amp;nbsp;있지만&amp;nbsp;브랜드는&amp;nbsp;없을&amp;nbsp;때) &lt;br /&gt;바이오산업 &lt;br /&gt;CRO(위탁연구) &lt;br /&gt;CDO(위탁개발) &lt;br /&gt;CMO(위탁생산)&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제 5장 사업 소유구조의 선택&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;기본적인 기업 소유구조&lt;/li&gt;
&lt;li&gt;개인기업(개인사업자)&lt;/li&gt;
&lt;li&gt;파트너쉽&lt;/li&gt;
&lt;li&gt;주식회사&lt;/li&gt;
&lt;li&gt;기업확장: 인수와 합병&lt;/li&gt;
&lt;li&gt;프랜차이즈&lt;/li&gt;
&lt;li&gt;협동조합&lt;/li&gt;
&lt;li&gt;개인기업,&amp;nbsp;파트너십,&amp;nbsp;회사의&amp;nbsp;장단점 &lt;br /&gt;-개인사업자의&amp;nbsp;장점&amp;nbsp; &lt;br /&gt;1.사업&amp;nbsp;시작과&amp;nbsp;철수가&amp;nbsp;용이함 &lt;br /&gt;2.자신이&amp;nbsp;오너가&amp;nbsp;됨 &lt;br /&gt;3.사업체&amp;nbsp;소유의&amp;nbsp;자부심이&amp;nbsp;생김 &lt;br /&gt;4.사업&amp;nbsp;이익을&amp;nbsp;가질&amp;nbsp;수&amp;nbsp;있음 &lt;br /&gt;-개인&amp;nbsp;사업의&amp;nbsp;단점 &lt;br /&gt;1.무한&amp;nbsp;책임.&amp;nbsp;사업의&amp;nbsp;소유주가&amp;nbsp;사업체의&amp;nbsp;모든&amp;nbsp;채무를&amp;nbsp;부담해야함. &lt;br /&gt;2.제한적&amp;nbsp;재무&amp;nbsp;자원.&amp;nbsp;아무리&amp;nbsp;자본이&amp;nbsp;많아도&amp;nbsp;공장을&amp;nbsp;세우거나&amp;nbsp;할&amp;nbsp;수&amp;nbsp;없음 &lt;br /&gt;3.경영의&amp;nbsp;어려움.&amp;nbsp;곡난도&amp;nbsp;회계 &lt;br /&gt;4.엄청난&amp;nbsp;시간&amp;nbsp;투자&amp;nbsp;필요 &lt;br /&gt;5.부가&amp;nbsp;혜택&amp;nbsp;없음 &lt;br /&gt;6.사업의&amp;nbsp;영속성&amp;nbsp;제약.&amp;nbsp;수명있음. &lt;br /&gt;&lt;br /&gt;-파트너쉽(동업)의&amp;nbsp;장점 &lt;br /&gt;1.재무적&amp;nbsp;자원이&amp;nbsp;더&amp;nbsp;많아짐 &lt;br /&gt;2.공동경영&amp;nbsp;및&amp;nbsp;기술과&amp;nbsp;지식의&amp;nbsp;상호&amp;nbsp;보완&amp;nbsp;및&amp;nbsp;시너지&amp;nbsp;창출&amp;nbsp;가능 &lt;br /&gt;3.생존율&amp;nbsp;더&amp;nbsp;높아짐 &lt;br /&gt;4.특별세&amp;nbsp;없음 &lt;br /&gt;-파트너쉽의&amp;nbsp;단점 &lt;br /&gt;1.무한책임 &lt;br /&gt;2.이익분배 &lt;br /&gt;3.파트너간&amp;nbsp;의견&amp;nbsp;불일치 &lt;br /&gt;4.사업&amp;nbsp;청산의&amp;nbsp;어려움 &lt;br /&gt;&lt;br /&gt;-주식회사(전통적인&amp;nbsp;회사)의&amp;nbsp;장점 &lt;br /&gt;1.유한&amp;nbsp;책임 &lt;br /&gt;2.더&amp;nbsp;많은&amp;nbsp;투자금액&amp;nbsp;유치&amp;nbsp;가능 &lt;br /&gt;3.규모&amp;nbsp;큼 &lt;br /&gt;4.영속성&amp;nbsp;길다. &lt;br /&gt;5.소유권&amp;nbsp;변경이&amp;nbsp;용이하다. &lt;br /&gt;6.능력&amp;nbsp;있는&amp;nbsp;종업원을&amp;nbsp;유치할&amp;nbsp;수&amp;nbsp;있다.&amp;nbsp; &lt;br /&gt;7.소유와&amp;nbsp;경영이&amp;nbsp;분리되어있다. &lt;br /&gt;-주식회사의&amp;nbsp;단점 &lt;br /&gt;1.초기&amp;nbsp;비용이&amp;nbsp;많이&amp;nbsp;든다. &lt;br /&gt;2.방대한&amp;nbsp;서류&amp;nbsp;작업이&amp;nbsp;필요하다. &lt;br /&gt;3.이중&amp;nbsp;과세 &lt;br /&gt;4.이중&amp;nbsp;납세&amp;nbsp;신고서 &lt;br /&gt;5.규모가&amp;nbsp;크다. &lt;br /&gt;6.사업&amp;nbsp;청산에&amp;nbsp;어려움이&amp;nbsp;있다. &lt;br /&gt;7.주주와&amp;nbsp;이사회와의&amp;nbsp;잠재적&amp;nbsp;갈등이&amp;nbsp;존재한다. &lt;br /&gt;&lt;br /&gt;-프랜차이즈(서비스,&amp;nbsp;상호,&amp;nbsp;브랜드&amp;nbsp;권리를&amp;nbsp;판매)의&amp;nbsp;장점 &lt;br /&gt;1.관리&amp;nbsp;및&amp;nbsp;마케팅을&amp;nbsp;지원받는다. &lt;br /&gt;2.그러면서&amp;nbsp;개인이&amp;nbsp;가게를&amp;nbsp;소유할&amp;nbsp;수&amp;nbsp;있다. &lt;br /&gt;3.전국적&amp;nbsp;인지도가&amp;nbsp;쌓여있다. &lt;br /&gt;4.재정&amp;nbsp;조언&amp;nbsp;및&amp;nbsp;지원을&amp;nbsp;받을&amp;nbsp;수&amp;nbsp;있다. &lt;br /&gt;5.사업&amp;nbsp;실패율이&amp;nbsp;낮다. &lt;br /&gt;-프랜차이즈의&amp;nbsp;단점 &lt;br /&gt;1.창업&amp;nbsp;비용이&amp;nbsp;높다. &lt;br /&gt;2.이익을&amp;nbsp;공유해야&amp;nbsp;한다. &lt;br /&gt;3.경영&amp;nbsp;규제가&amp;nbsp;있다. &lt;br /&gt;4.연미복&amp;nbsp;효과가&amp;nbsp;있다. &lt;br /&gt;5.매각에&amp;nbsp;제약이&amp;nbsp;있다. &lt;br /&gt;6.프랜차이즈&amp;nbsp;본사의&amp;nbsp;부정을&amp;nbsp;탈&amp;nbsp;수&amp;nbsp;있다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제 6장 기업가정신과 중소기업 창업&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;미국 기업가들의 일자리 창출 능력&lt;/li&gt;
&lt;li&gt;사람들이 기업가가 되기 위해 도전하는 이유&lt;/li&gt;
&lt;li&gt;소규모 기업 창업&lt;/li&gt;
&lt;li&gt;소기업 운영에 관해 배우기&lt;/li&gt;
&lt;li&gt;소기업 경영하기&lt;/li&gt;
&lt;li&gt;글로벌 진출 : 소기업의 전망&lt;/li&gt;
&lt;li&gt;중소기업의&amp;nbsp;성공과&amp;nbsp;실패 &lt;br /&gt;-실패이유 &lt;br /&gt;경영능력&amp;nbsp;부족,&amp;nbsp;불충분한&amp;nbsp;자금&amp;nbsp;계획,&amp;nbsp;잘못된&amp;nbsp;업종&amp;nbsp;선택 &lt;br /&gt;-중소기업을&amp;nbsp;잘&amp;nbsp;경영하려면? &lt;br /&gt;1.다른사람으로부터&amp;nbsp;배우기&amp;nbsp;:&amp;nbsp;중소기업과&amp;nbsp;창업에&amp;nbsp;관한&amp;nbsp;강좌&amp;nbsp;수강하기,&amp;nbsp;성공한&amp;nbsp;지역&amp;nbsp;사업가&amp;nbsp;밑에서&amp;nbsp;일하며&amp;nbsp;배우기 &lt;br /&gt;2.경험&amp;nbsp;쌓기&amp;nbsp;:&amp;nbsp;해당&amp;nbsp;분야에서&amp;nbsp;3년&amp;nbsp;정도&amp;nbsp;경험&amp;nbsp;쌓기,&amp;nbsp;이후&amp;nbsp;부업으로&amp;nbsp;소기업&amp;nbsp;창업하기 &lt;br /&gt;3.성공한&amp;nbsp;기업의&amp;nbsp;인수&amp;nbsp;:&amp;nbsp;견습생으로&amp;nbsp;봉사한&amp;nbsp;다음,&amp;nbsp;나중에&amp;nbsp;오너가&amp;nbsp;물러날&amp;nbsp;때&amp;nbsp;인수하기 &lt;br /&gt;또&amp;nbsp;실패이유가&amp;nbsp;뭘까? &lt;br /&gt;-소규모&amp;nbsp;테스트&amp;nbsp;없이&amp;nbsp;시장&amp;nbsp;진입 &lt;br /&gt;-과소&amp;nbsp;혹은&amp;nbsp;과대&amp;nbsp;계상된&amp;nbsp;제품/서비스&amp;nbsp;가격 &lt;br /&gt;-시장을&amp;nbsp;구축하는데&amp;nbsp;필요한&amp;nbsp;시간을&amp;nbsp;간과 &lt;br /&gt;-자본금&amp;nbsp;부족 &lt;br /&gt;-과다한&amp;nbsp;자본금을&amp;nbsp;유치하고&amp;nbsp;올바른&amp;nbsp;사용처를&amp;nbsp;선정하지&amp;nbsp;않음 &lt;br /&gt;-경험&amp;nbsp;부족과&amp;nbsp;산업과&amp;nbsp;시장에&amp;nbsp;대한&amp;nbsp;학습&amp;nbsp;부재 &lt;br /&gt;-상환&amp;nbsp;시기와&amp;nbsp;방법을&amp;nbsp;구체적으로&amp;nbsp;계획하지&amp;nbsp;않고&amp;nbsp;차입 &lt;br /&gt;-부족한&amp;nbsp;자본금으로&amp;nbsp;사업&amp;nbsp;시작 &lt;br /&gt;-사업&amp;nbsp;유보금이나&amp;nbsp;예상치&amp;nbsp;못한&amp;nbsp;지출에&amp;nbsp;대한&amp;nbsp;대비&amp;nbsp;부재 &lt;br /&gt;-과다&amp;nbsp;신용&amp;nbsp;구매 &lt;br /&gt;-신용도&amp;nbsp;과다&amp;nbsp;연장 &lt;br /&gt;-신용도&amp;nbsp;급속히&amp;nbsp;소진 &lt;br /&gt;-정확하고&amp;nbsp;완벽한&amp;nbsp;기록&amp;nbsp;부재로&amp;nbsp;경영자가&amp;nbsp;문제&amp;nbsp;인식&amp;nbsp;못함 &lt;br /&gt;-개인적&amp;nbsp;낭비벽을&amp;nbsp;사업에서도&amp;nbsp;버리지&amp;nbsp;못함 &lt;br /&gt;-사업&amp;nbsp;주기에&amp;nbsp;대한&amp;nbsp;이해&amp;nbsp;부족 &lt;br /&gt;-세금,&amp;nbsp;보험,&amp;nbsp;기타&amp;nbsp;비용에&amp;nbsp;대한&amp;nbsp;이해&amp;nbsp;부족 &lt;br /&gt;-스스로&amp;nbsp;근무&amp;nbsp;시간을&amp;nbsp;조절하지&amp;nbsp;못하고&amp;nbsp;태만 &lt;br /&gt;&lt;br /&gt;창업&amp;nbsp;계획하기&amp;nbsp;-&amp;nbsp;사업계획서에&amp;nbsp;대하여 &lt;br /&gt;사업의&amp;nbsp;성격,&amp;nbsp;목표시장,&amp;nbsp;경쟁자에&amp;nbsp;비해&amp;nbsp;자사가&amp;nbsp;가진&amp;nbsp;우위,&amp;nbsp;오너가&amp;nbsp;가진&amp;nbsp;자원과&amp;nbsp;자격&amp;nbsp;등에&amp;nbsp;대해&amp;nbsp;자세히&amp;nbsp;적어&amp;nbsp;놓은&amp;nbsp;글. &lt;br /&gt;잠재적&amp;nbsp;소유주가&amp;nbsp;구체적으로&amp;nbsp;무엇을&amp;nbsp;제공할&amp;nbsp;것인지&amp;nbsp;압박하는&amp;nbsp;수단이&amp;nbsp;된다. &lt;br /&gt;은행가,&amp;nbsp;투자자와의&amp;nbsp;미팅&amp;nbsp;전&amp;nbsp;준비&amp;nbsp;필수&amp;nbsp;요건 &lt;br /&gt;&lt;br /&gt;좋은&amp;nbsp;사업&amp;nbsp;계획서&amp;nbsp;작성하기 &lt;br /&gt;1.좋은&amp;nbsp;계획서&amp;nbsp;작성을&amp;nbsp;위해서는&amp;nbsp;오랜&amp;nbsp;준비시간&amp;nbsp;필요 &lt;br /&gt;2.경영자에&amp;nbsp;대한&amp;nbsp;훌륭한&amp;nbsp;핵심&amp;nbsp;요약은&amp;nbsp;관심을&amp;nbsp;끌고&amp;nbsp;잠재&amp;nbsp;투자자들로&amp;nbsp;하여금&amp;nbsp;더&amp;nbsp;읽어보고싶게&amp;nbsp;유인함 &lt;br /&gt;3.사업계획서에&amp;nbsp;올바른&amp;nbsp;정보를&amp;nbsp;담는&amp;nbsp;것도&amp;nbsp;중요하지만&amp;nbsp;누구에게&amp;nbsp;제시하는가가&amp;nbsp;더&amp;nbsp;중요함(올바른&amp;nbsp;자금&amp;nbsp;조달처&amp;nbsp;찾기) &lt;br /&gt;1)경영자&amp;nbsp;요약 &lt;br /&gt;2)회사&amp;nbsp;배경 &lt;br /&gt;3)경영&amp;nbsp;관리&amp;nbsp;팀 &lt;br /&gt;4)재무&amp;nbsp;계획 &lt;br /&gt;5)필수&amp;nbsp;자본 &lt;br /&gt;6)마케팅&amp;nbsp;계획 &lt;br /&gt;7)입지&amp;nbsp;분석 &lt;br /&gt;8)제조&amp;nbsp;계획 &lt;br /&gt;9)첨부 &lt;br /&gt;자금을&amp;nbsp;조달하기&amp;nbsp;위해서는&amp;nbsp;지역개발금융기관에서&amp;nbsp;특히&amp;nbsp;저소득&amp;nbsp;지역을&amp;nbsp;위해&amp;nbsp;자금을&amp;nbsp;대출해주고&amp;nbsp;자문도&amp;nbsp;제공한다. &lt;br /&gt;-엔젤투자자&amp;nbsp;:&amp;nbsp;잠재적으로&amp;nbsp;유망한&amp;nbsp;기업들이&amp;nbsp;시장에&amp;nbsp;공개되기&amp;nbsp;전에&amp;nbsp;개인&amp;nbsp;자금을&amp;nbsp;투자하는&amp;nbsp;사람 &lt;br /&gt;-크라우드&amp;nbsp;펀딩&amp;nbsp;:&amp;nbsp;한&amp;nbsp;기업이나&amp;nbsp;제품을&amp;nbsp;지원하기&amp;nbsp;위해&amp;nbsp;다수의&amp;nbsp;개인들이&amp;nbsp;기부하는&amp;nbsp;돈 &lt;br /&gt;-벤처투자자&amp;nbsp;:&amp;nbsp;일정&amp;nbsp;지분을&amp;nbsp;댓가로&amp;nbsp;신규&amp;nbsp;기업에게&amp;nbsp;투자하는&amp;nbsp;개인&amp;nbsp;혹은&amp;nbsp;회사&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제 7장 관리와 리더십&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;진화되는 관리자의 역할&lt;/li&gt;
&lt;li&gt;관리의 4가지 기능&lt;/li&gt;
&lt;li&gt;계획과 의사결정&lt;/li&gt;
&lt;li&gt;조직: 통일된 체계 만들기&lt;/li&gt;
&lt;li&gt;지휘: 지속적인 비전과 가치 제공&lt;/li&gt;
&lt;li&gt;통제: 성과 지향&lt;/li&gt;
&lt;li&gt;SWOT&amp;nbsp;분석&amp;nbsp;-&amp;nbsp;조직의&amp;nbsp;강점,&amp;nbsp;약점,&amp;nbsp;기회와&amp;nbsp;위협요인을&amp;nbsp;분석하기&amp;nbsp;위해&amp;nbsp;사용되는&amp;nbsp;계획&amp;nbsp;도구 &lt;br /&gt;리더십의&amp;nbsp;유형&amp;nbsp; &lt;br /&gt;1.전제적&amp;nbsp;리더십&amp;nbsp;:&amp;nbsp;다른&amp;nbsp;사람과&amp;nbsp;상의없이&amp;nbsp;독단적으로&amp;nbsp;의사결정을&amp;nbsp;내린다.&amp;nbsp;관리자가&amp;nbsp;결정&amp;nbsp;사항을&amp;nbsp;설득한다.&amp;nbsp;관리자가&amp;nbsp;의견을&amp;nbsp;제시하고&amp;nbsp;질문을&amp;nbsp;수행한다.&amp;nbsp;군대,&amp;nbsp;경찰&amp;nbsp;등&amp;nbsp;계급이&amp;nbsp;존재할&amp;nbsp;때&amp;nbsp;쓴다.&amp;nbsp;위&amp;nbsp;계급의&amp;nbsp;사람이&amp;nbsp;많이&amp;nbsp;알고,&amp;nbsp;숙련된&amp;nbsp;경우.&amp;nbsp;단순업무,&amp;nbsp;제조업에&amp;nbsp;적합하다.&amp;nbsp;명확한&amp;nbsp;지시와&amp;nbsp;지침이&amp;nbsp;필요한&amp;nbsp;신참이나,&amp;nbsp;위기&amp;nbsp;상황에&amp;nbsp;효과적이므로. &lt;br /&gt;2.참여적&amp;nbsp;(민주적)리더심&amp;nbsp;:&amp;nbsp;관리자와&amp;nbsp;종업원이&amp;nbsp;협의하여&amp;nbsp;의사결정을&amp;nbsp;내린다.&amp;nbsp;관리자가&amp;nbsp;잠정적인&amp;nbsp;결정&amp;nbsp;사항에&amp;nbsp;대해&amp;nbsp;발표한다.&amp;nbsp;관리자가&amp;nbsp;문제를&amp;nbsp;제시하고&amp;nbsp;의견을&amp;nbsp;수렴한&amp;nbsp;후&amp;nbsp;의사를&amp;nbsp;결정한다.&amp;nbsp;관리자가&amp;nbsp;한계를&amp;nbsp;규정하고&amp;nbsp;그룹에&amp;nbsp;의사결정할&amp;nbsp;것을&amp;nbsp;부탁한다.&amp;nbsp;제일&amp;nbsp;많은&amp;nbsp;사례로,&amp;nbsp;합리적&amp;nbsp;지시를&amp;nbsp;수용하고,&amp;nbsp;무조건&amp;nbsp;수용하는&amp;nbsp;것은&amp;nbsp;아니다. &lt;br /&gt;3.자유방임형&amp;nbsp;리더십&amp;nbsp;:&amp;nbsp;관리자가&amp;nbsp;설정한&amp;nbsp;목표를&amp;nbsp;달성하기&amp;nbsp;위해서라면&amp;nbsp;직원이&amp;nbsp;비교적&amp;nbsp;자유롭게&amp;nbsp;무엇이든지&amp;nbsp;할&amp;nbsp;수&amp;nbsp;있는&amp;nbsp;형태.&amp;nbsp;관리자가&amp;nbsp;상급자에&amp;nbsp;의해&amp;nbsp;규정된&amp;nbsp;범위&amp;nbsp;안에서&amp;nbsp;종업원들이&amp;nbsp;스스로&amp;nbsp;기능할&amp;nbsp;수&amp;nbsp;있도록&amp;nbsp;용인한다.&amp;nbsp;&amp;nbsp;알아서하는데,&amp;nbsp;월말에&amp;nbsp;실적만&amp;nbsp;보자.&amp;nbsp;전문&amp;nbsp;영역이&amp;nbsp;다르므로,&amp;nbsp;터치하지&amp;nbsp;않는다.&amp;nbsp;보험,&amp;nbsp;영업직,&amp;nbsp;판매직,&amp;nbsp;전문직 &lt;br /&gt;&lt;br /&gt;관리자의&amp;nbsp;권한&amp;nbsp;행사가&amp;nbsp;많을수록,&amp;nbsp;상사&amp;nbsp;중심의&amp;nbsp;리더십이&amp;nbsp;되고,&amp;nbsp;종업원의&amp;nbsp;자유는&amp;nbsp;이에&amp;nbsp;반비례한다.&lt;/li&gt;
&lt;/ul&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;제 9장 생산 및 오퍼레이션스 관리&lt;/p&gt;
&lt;ul style=&quot;list-style-type: circle;&quot; data-ke-list-type=&quot;circle&quot;&gt;
&lt;li&gt;서비스업의&amp;nbsp;생산,&amp;nbsp;운영관리가&amp;nbsp;중요해진다.&amp;nbsp;이&amp;nbsp;때,&amp;nbsp;서비스는&amp;nbsp;고객의&amp;nbsp;흐름에&amp;nbsp;따라&amp;nbsp;흘러가므로,&amp;nbsp;고객이&amp;nbsp;서비스를&amp;nbsp;받기&amp;nbsp;위해&amp;nbsp;기다리고&amp;nbsp;있다면&amp;nbsp;생산이&amp;nbsp;잘&amp;nbsp;안되고&amp;nbsp;있다는&amp;nbsp;뜻이다.&amp;nbsp; &lt;br /&gt;서비스업인&amp;nbsp;호텔과&amp;nbsp;공항의&amp;nbsp;사례를&amp;nbsp;보면,&amp;nbsp;식당&amp;nbsp;서비스,&amp;nbsp;고급&amp;nbsp;엘리베이터,&amp;nbsp;신속한&amp;nbsp;프론트데스크,&amp;nbsp;로비&amp;nbsp;장식,&amp;nbsp;객실&amp;nbsp;푸드&amp;nbsp;등이&amp;nbsp;운영관리이다.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;</description>
      <category>강의내용 복습</category>
      <author>코오오 코오</author>
      <guid isPermaLink="true">https://fightingway.tistory.com/29</guid>
      <comments>https://fightingway.tistory.com/29#entry29comment</comments>
      <pubDate>Sun, 23 Apr 2023 22:29:01 +0900</pubDate>
    </item>
    <item>
      <title>Greedy 알고리즘 - Huffman Code</title>
      <link>https://fightingway.tistory.com/28</link>
      <description>&lt;p data-ke-size=&quot;size16&quot;&gt;greedy 알고리즘 일곱 번째 문제&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;h4 data-ke-size=&quot;size20&quot;&gt;&lt;i&gt;&lt;b&gt;7.Huffman Code&lt;/b&gt;&lt;/i&gt;&lt;/h4&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-텍스트를 압축할때, 파일에 빈번히 나타나는 문자에는 짧은 이진 코드를 할당하고&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;드물게 나타나는 문자에는 긴 이진 코드를 할당하는 것이다.&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-이 때 문자를 표현하기 위해 트리를 이용한다.&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;-방법 1. min-priority queue를 사용하는 방법&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1682234066089&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;1.각 문자 당 노드를 만들고, 그 문자의 빈도수를 노드에 저장
2.n개의 노드의 빈도수에 대해 우선순위 큐 Q를 만든다.
while(Q에 있는 노드 수 &amp;gt;=2){
  빈도수가 가장 작은 2개의 노드 (A와 B)를 Q에서 제거.
  새 노드 N을 만들고, A와 B를 N의 자식 노드로 만든다.
  N의 빈도수 = A의 빈도수 +B의 빈도수
  노드N을 Q에 삽입한다.}
return Q&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;-Time Complexity&lt;/b&gt;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;n개 노드 만들기 : O(n)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;+&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;heap 만들기. Insert n번 발생 : Nlogn&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;+&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;Q에 있는 노드 수가 1개 남을때까지 반복. : O(n)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;반복 안에서 Delete, Insert 수행 : O(logn)+O(logn)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;=O(n)+O(nlogn)+n{O(logn)+O(logn)} = O(nlogn)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;-전체 흐름&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;20230423_074104133_iOS.png&quot; data-origin-width=&quot;1270&quot; data-origin-height=&quot;1211&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/blLgS4/btsbTv3amlN/FcYkimCmAtOoPWqn5HulB1/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/blLgS4/btsbTv3amlN/FcYkimCmAtOoPWqn5HulB1/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/blLgS4/btsbTv3amlN/FcYkimCmAtOoPWqn5HulB1/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FblLgS4%2FbtsbTv3amlN%2FFcYkimCmAtOoPWqn5HulB1%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;724&quot; height=&quot;690&quot; data-filename=&quot;20230423_074104133_iOS.png&quot; data-origin-width=&quot;1270&quot; data-origin-height=&quot;1211&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;20230423_074129061_iOS.png&quot; data-origin-width=&quot;933&quot; data-origin-height=&quot;1136&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/Qus66/btsb1RxjnTK/S71JBMSVz0AW8dI129ddmK/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/Qus66/btsb1RxjnTK/S71JBMSVz0AW8dI129ddmK/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/Qus66/btsb1RxjnTK/S71JBMSVz0AW8dI129ddmK/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FQus66%2Fbtsb1RxjnTK%2FS71JBMSVz0AW8dI129ddmK%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;419&quot; height=&quot;510&quot; data-filename=&quot;20230423_074129061_iOS.png&quot; data-origin-width=&quot;933&quot; data-origin-height=&quot;1136&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size18&quot;&gt;&lt;b&gt;-방법2 Sorting을 사용하는 방법&lt;/b&gt;&lt;/p&gt;
&lt;pre id=&quot;code_1682234618291&quot; class=&quot;cpp&quot; data-ke-language=&quot;cpp&quot; data-ke-type=&quot;codeblock&quot;&gt;&lt;code&gt;1.Initial Sequence T sorted by frequency//빈도수에 따라 오름차순 정렬
2.while(#of T&amp;gt;=){//T가 하나 남을때까지 반복
3.  Combine lowest two into sub-tree //가장 작은 2개를 sub tree에 넣고 더해
4.  Move it correct place} //다시 insert
5.return T&lt;/code&gt;&lt;/pre&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;-Time Complexity&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;1.정렬 : O(nlogn)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;+&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;2.2line부터 n번 반복&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;3. constant&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;4.삽입 : O(logn)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;=O(nlogn)+O(nlogn)=O(nlogn)&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p data-ke-size=&quot;size16&quot;&gt;&lt;b&gt;-전체 흐름&lt;/b&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure class=&quot;imageblock alignCenter&quot; data-ke-mobileStyle=&quot;widthOrigin&quot; data-filename=&quot;20230423_073008812_iOS.png&quot; data-origin-width=&quot;1116&quot; data-origin-height=&quot;858&quot;&gt;&lt;span data-url=&quot;https://blog.kakaocdn.net/dn/onyjU/btsbTpoq9zC/10GXcNUdLbAbWQxTguwR8K/img.png&quot; data-phocus=&quot;https://blog.kakaocdn.net/dn/onyjU/btsbTpoq9zC/10GXcNUdLbAbWQxTguwR8K/img.png&quot;&gt;&lt;img src=&quot;https://blog.kakaocdn.net/dn/onyjU/btsbTpoq9zC/10GXcNUdLbAbWQxTguwR8K/img.png&quot; srcset=&quot;https://img1.daumcdn.net/thumb/R1280x0/?scode=mtistory2&amp;fname=https%3A%2F%2Fblog.kakaocdn.net%2Fdn%2FonyjU%2FbtsbTpoq9zC%2F10GXcNUdLbAbWQxTguwR8K%2Fimg.png&quot; onerror=&quot;this.onerror=null; this.src='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png'; this.srcset='//t1.daumcdn.net/tistory_admin/static/images/no-image-v1.png';&quot; loading=&quot;lazy&quot; width=&quot;556&quot; height=&quot;427&quot; data-filename=&quot;20230423_073008812_iOS.png&quot; data-origin-width=&quot;1116&quot; data-origin-height=&quot;858&quot;/&gt;&lt;/span&gt;&lt;/figure&gt;
&lt;/p&gt;</description>
      <category>강의내용 복습/컴퓨터 알고리즘</category>
      <author>코오오 코오</author>
      <guid isPermaLink="true">https://fightingway.tistory.com/28</guid>
      <comments>https://fightingway.tistory.com/28#entry28comment</comments>
      <pubDate>Sun, 23 Apr 2023 16:43:20 +0900</pubDate>
    </item>
  </channel>
</rss>