오늘은
주말이었던 어제는 오랜만에 찜질방에 다녀왔습니다
정말정말 개운하게 목욕과 사우나를 하고 상쾌한 마음으로
오늘 새로운 한 주를 시작하였습니다
열심히 공부를 하고 무엇인가에 몰두하는 만큼
충분한 휴식도 중요한 것 같습니다
Spring 공부
<댓글 수정/삭제>
수정 -> 수정페이지 (해당 댓글 가져오기 - 상세보기 서비스) : GET
수정처리-> update 서비스 : POST
* detail.jsp
<P>
<a href="/reply/update?boardId=${board.id}&id=${reply.id}">수정</a> |
<a href="/reply/delete?boardId=${board.id}&id=${reply.id}"
onclick="return confirm('정말로 삭제하시겠습니까?')">삭제</a>
</P>
<c:choose>
<c:when test="${empty reply.updateTime}">
(작성일 : <fmt:formatDate value="${reply.createTime}"
pattern="yyy-MM-dd HH:mm:ss" />)
</c:when>
<c:otherwise>
(수정일 : <fmt:formatDate value="${reply.updateTime}"
pattern="yyy-MM-dd HH:mm:ss" />)
</c:otherwise>
</c:choose>
* ReplyController
public class ReplyController {
// 삭제하기
@GetMapping("/delete")
public String replyDelete(@RequestParam("boardId") Long boardId,
@RequestParam("id") Long id) {
// 삭제할 땐 댓글 번호를 파라미터로 보내줌
replyService.delete(id);
return "redirect:/board?id=" + boardId;
}
// 수정 페이지 요청
@GetMapping("/update")
public String updateForm(@RequestParam("boardId") Long boardId,
@RequestParam("id") Long id,
Model model) {
// 해당 댓글 가져오기
ReplyDTO replyDTO = replyService.findById(id);
model.addAttribute("reply", replyDTO);
return "/board/replyupdate";
}
// 댓글 수정 처리
@PostMapping("/update")
public String update(@ModelAttribute ReplyDTO replyDTO) {
log.info(""+replyDTO);
replyService.update(replyDTO);
return "redirect:/board?id=" + replyDTO.getBoardId();
}
}
* ReplyService
public interface ReplyService {
void delete(Long id);
ReplyDTO findById(Long id);
void update(ReplyDTO replyDTO);
}
* ReplyServiceImpl
public class ReplyServiceImpl implements ReplyService{
@Override
public void delete(Long id) {
replyMapper.delete(id);
}
@Override
public ReplyDTO findById(Long id) {
return replyMapper.findById(id);
}
@Override
public void update(ReplyDTO replyDTO) {
replyMapper.update(replyDTO);
}
}
* ReplyMapper
public interface ReplyMapper {
void delete(Long id);
ReplyDTO findById(Long id);
void update(ReplyDTO replyDTO);
}
* ReplyMapper.xml
<mapper namespace="cohttp://m.khit.web.mapper.ReplyMapper">
<delete id="delete">
delete from reply where id = #{id}
</delete>
<select id="findById" resultType="cohttp://m.khit.web.dto.ReplyDTO">
select * from reply where id = #{id};
</select>
<update id="update">
update reply
set replycontent = #{replyContent}, updatetime = now()
where id = #{id};
</update>
</mapper>
<<todo project>>
- Spring(FrameWork) + Jsp(화면구현) + mybatis(DB SQL 처리)
project 이름 : todoweb
기능구현 상세
- 등록 기능
- 목록 보기(페이징, 검색)
- 상세 보기
- 수정/삭제
디자인 라이브러리:부트스트랩
컨택스트: cohttp://m.khit.todo.web
의존성 주입 - pom.xml
jdk: 11
Spring version:5.2.7
1. lombok
2. mysql driver
3. mybatis
4. spring-mybatis
* HomeController
@Controller
public class HomeController {
@GetMapping("/")
public String index() {
return "index";
}
}
* TodoController
package com.khit.todoweb.controller;
import java.util.List;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import com.khit.todoweb.dto.TodoDTO;
import com.khit.todoweb.service.TodoService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@AllArgsConstructor
@Slf4j
@RequestMapping("/todo")
@Controller
public class TodoController {
private TodoService todoService;
@GetMapping("/register")
public String registerForm() {
return "/todo/register";
}
@PostMapping("/register")
public String register(@ModelAttribute TodoDTO todoDTO ) {
log.info("todoDTO:" + todoDTO);
todoService.insert(todoDTO);
return "/todo/register";
}
@GetMapping("/list")
public String todoList(Model model) {
List<TodoDTO> todoDTOList = todoService.findAll();
model.addAttribute("todoList", todoDTOList);
return "/todo/list";
}
}
* TodoService
package com.khit.todoweb.service;
import cohttp://m.khit.todoweb.dto.TodoDTO;
public interface TodoService {
void insert(TodoDTO todoDTO);
List<TodoDTO> findAll();
}
* TodoServiceImpl
package com.khit.todoweb.service;
import java.util.List;
import org.modelmapper.ModelMapper;
import org.springframework.stereotype.Service;
import com.khit.todoweb.dto.TodoDTO;
import com.khit.todoweb.mapper.TodoMapper;
import com.khit.todoweb.vo.TodoVO;
import lombok.AllArgsConstructor;
@AllArgsConstructor
@Service
public class TodoServiceImpl implements TodoService{
private TodoMapper todoMapper;
private ModelMapper modelMapper;
@Override
public void insert(TodoDTO todoDTO) {
// DTO를 VO로 변환해야 -> DB에 데이터를 저장
// 1. 모듈(ModelMapper)을 사용안한 경우
/*TodoVO todoVO = TodoVO.builder()
.title(todoDTO.getTitle())
.writer(todoDTO.getWriter())
.build();*/
// todoMapper.insert(todoVO);
// 2. 모듈(ModelMapper)을 사용한 경우
TodoVO todoVO = modelMapper.map(todoDTO, TodoVO.class);
todoMapper.insert(todoVO);
}
@Override
public List<TodoDTO> findAll() {
return null;
}
@Override
public List<TodoDTO> findAll() {
// vo를 dto로 변환해야 -> DB에서 데이터를 꺼냄
// vo리스트 데이터 가져오기
List<TodoVO> voList = todoMapper.findAll();
// vo 리스트를 dto로 저장하고 반환함(람다식으로 구현)
List<TodoDTO> dtoList = voList.stream()
.map(vo -> modelMapper.map(vo, TodoDTO.class))
.collect(Collectors.toList());
return dtoList;
}
}
* TodoMapper
package cohttp://m.khit.todoweb.mapper;
import java.util.List;
import cohttp://m.khit.todoweb.vo.TodoVO;
public interface TodoMapper {
public String getTime(); // 현재 시간 테스트
public void insert(TodoVO todoVO); //등록하기
List<TodoVO> findAll();
}
* TodoMapper.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cohttp://m.khit.todoweb.mapper.TodoMapper">
<select id="getTime" resultType="String">
select now()
</select>
<insert id="insert">
insert into tbl_todo(title, writer)
values(#{title}, #{writer})
</insert>
<select id="findAll" resultType="cohttp://m.khit.todoweb.vo.TodoVO">
select * from tbl_todo order by tno desc
</select>
</mapper>
스프링부트
Mapper = VO 사용
- VO : TodoVO (DB연동, SQL)
- Test : Junit = 오류가 있는지 테스트
- ModelMapper jar 의존성 주입
-> @Bean으로 등록해야함
-> config클래스 생성 - @Configuration
* pom.xml
<dependency>
<groupId>org.modelmapper</groupId>
<artifactId>modelmapper</artifactId>
<version>2.4.5</version>
</dependency>
* TodoConfig
package cohttp://m.khit.todoweb.config;
import org.modelmapper.ModelMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
// 설정파일로 만들어주는 어노테이션
@Configuration
public class TodoConfig {
// ModelMapper를 빈으로 등록함
@Bean
public ModelMapper modelMapper() {
return new ModelMapper();
}
}
* TodoServiceImpl
import org.modelmapper.ModelMapper;
@AllArgsConstructor
@Service
public class TodoServiceImpl implements TodoService{
private ModelMapper modelMapper;
@Override
public void insert(TodoDTO todoDTO) {
TodoVO todoVO = modelMapper.map(todoDTO, TodoVO.class);
todoMapper.insert(todoVO);
}
}
* TodoVO
package cohttp://m.khit.todoweb.vo;
import java.sql.Timestamp;
import cohttp://m.khit.todoweb.dto.TodoDTO;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Builder
@NoArgsConstructor //기본 생성자
@AllArgsConstructor //파라미터가 있는 생성자
@Data //Getter, Setter, ToString
public class TodoVO {
//필드
private Long tno;
private String title;
private String writer;
private Timestamp createDate;
}
Service, Controller = DTO 사용
- DTO : TodoDTO (전달, 유효성검사)
- 변환기 : 서비스계층
* TodoDTO
package cohttp://m.khit.todoweb.dto;
import java.sql.Timestamp;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Builder // getter, setter 를 쉽게 해줌
@NoArgsConstructor // 기본 생성자
@AllArgsConstructor // 매개변수(파라미터)가 있는 생성자
@Data // = Getter, Setter, ToString
public class TodoDTO {
// 필드
private Long tno;
private String title;
private String writer;
private Timestamp createDate;
}
React 공부
<<React Developer Tools>>
= chrome의 확장 도구
-> React Developer Tools 검색, 설치
=> f12 개발자 모드 -> >> -> Components 탭 선택
* Components 탭
= 개발중인 React의 component 계층 구조를 파악해서 보여준다
data와 key값도 보여준다
어떤 state, ref, useEffect를 가지고 있는지 까지도 보여준다
어떤 props를 받았는지도 보여준다
=> View Settings
-> Highlight updates when components render -> checked
= component가 re-rendering되는 것을 테두리로 시각화해서 보여준다
<<최적화>>
<연산 결과 재사용>
=> Memoization 기법 사용, 이해하기
= 현재 일기 데이터를 분석하는 함수 제작
해당 함수가 일기 데이터의 길이가 변화하지 않을 때 값을 다시 계산하지 않도록 하기
* Memoization
= 프로그래밍 기법에 가까운 내용
= 이미 계산 해 본 연산 결과를 기억 해 두었다가
동일한 계산을 시키면, 다시 연산하지 않고 기억 해 두었던 데이터를 반환 시키게 하는 방법
= 시험을 볼 때 이미 풀어본 문제는 다시 풀어보지 않아도 답을 알고 있는 것과 유사
= 연산 과정 최적화
=> 컴퓨터 : 용량만큼 충분한 답을 기억할 수 있음 + 절대 까먹지 않고, 절대 헷갈리지 않음
-> 나올 수 있는 모든 문제의 답을 외워버림
* useMemo() 함수
=> useMemo()함수로 Memoization하고싶은 함수의 코드를 감싸준다
첫번째 인자로 callback함수를 받아서 callback함수가 return하는 값
연산을 최적화 시켜주는 기능을 한다
* App.js
import { useMemo } from "react";
const App = () => {
// 최적화 함수
// => getDiaryAnalysis에 useMemo()함수를 활용하여
// return을 갖는 함수를 Memoization할 수 있다
const getDiaryAnalysis = useMemo(
// useMemo()함수로 Memoization하고싶은 함수의 코드를 감싸준다
// getDiaryAnalysis가 useMemo()함수를 호출한 결과값 처럼 바뀜
// 첫번째 인자로 callback함수를 호출하는 형태가 된다
() => {
if (data.length === 0) {
return { goodcount: 0, badCount: 0, goodRatio: 0 };
}
console.log("일기 분석 시작");
// 감정 점수에 따른 일기 분류
const goodCount = data.filter((it) => it.emotion >= 3).length;
const badCount = data.length - goodCount;
const goodRatio = (goodCount / data.length) * 100.0;
return { goodCount, badCount, goodRatio };
},
// getDiaryAnalysis함수를 호출한다고 하더라도
// 두번째 인자인 [data.length]가 변화하지 않는 이상
// 똑같은 return을 계산하지 않고 반환한다
[data.length]
// dependency array에 어떤 값이 변화할 때만 이 연산을 다시 수행 하도록 명시하게 되면
// 함수를 값처럼 사용을 해서 연산 최적화를 할 수 있다
);
// re-rendering이 될 때 다시한번 실행이 된다
// useMemo()를 활용하여 함수를 최적화하게 되면 그 함수는 더이상 함수가 아니게 된다
// useMemo()가 callback함수의 return 값을 return하기 때문에
// getDiaryAnalysis는 useMemo로부터 값만을 return 받게 된다
// 그렇기 때문에 함수가 아닌 값으로써 사용하게 된다
const { goodCount, badCount, goodRatio } = getDiaryAnalysis; //getDiaryAnalysis() X
return (
<div className="App">
{/* 받은 데이터 rendering */}
<div>전체 일기 : {data.length}</div>
<div>기분 좋은 일기 개수 : {goodCount}</div>
<div>기분 나쁜 일기 개수 : {badCount}</div>
<div>기분 좋은 일기 비율 : {goodRatio}</div>
</div>
);
};
2024. 01. 08 (월)
프로그래머 도전기 99일차 (2) | 2024.01.10 |
---|---|
프로그래머 도전기 98일차 (2) | 2024.01.10 |
프로그래머 도전기 96일차 (2) | 2024.01.05 |
프로그래머 도전기 95일차 (1) | 2024.01.04 |
프로그래머 도전기 94일차 (2) | 2024.01.03 |