본문 바로가기

신세계 국비과정/신세계 - Spring 공부

15주차 배운점 - Spring mybatis Todo 프로그램 (CRUD)

728x90
반응형

 

 

Todo 기능 개발(insert)

 

개발 순서 :


TodoMapper -> TodoService -> TodoController -> JSP

 

 

매퍼

 

TodoMapper interface

 

void insert(TodoVO todoVO);

 

 

TodoMapper.xml

<insert id="insert">--  세미콜론 안넣음, 원하는 쿼리작성
        insert into tbl_todo(title, dueDate, writer) values (#{title},#{dueDate},#{writer})
    </insert>

 

 

test

@Test
    public void testInsert(){

        TodoVO todoVO = TodoVO.builder()
                .title("titletest")
                .dueDate(LocalDate.of(2024,03,03))
                .writer("정휘제")
                .build();

        todoMapper.insert(todoVO);


    }

 

 

 

 

 

서비스

 

TodoService interface

public interface TodoService {

    void register(TodoDTO todoDTO);

}

 

TodoServiceImpl

 

DTO 받고 매퍼.insert 한테 VO로 줌

@Service
@Log4j2
@RequiredArgsConstructor
public class TodoServiceImpl implements TodoService{
    private final TodoMapper todoMapper;
    private final ModelMapper modelMapper;

    @Override
    public void register(TodoDTO todoDTO){
        log.info(modelMapper);
        TodoVO todoVO = modelMapper.map(todoDTO,TodoVO.class);

        log.info(todoVO);

        todoMapper.insert(todoVO);


    }

}

 

빈등록


root-context.xml에 추가

 

<context:component-scan base-package="com.ssg.todo.service" />

 

 

test

 

@Test
    public void testInsert(){

        TodoVO todoVO = TodoVO.builder()
                .title("titletest")
                .dueDate(LocalDate.of(2024,03,03))
                .writer("정휘제")
                .build();

        todoMapper.insert(todoVO);


    }

 

 

 

 


 

controller

 

String 반환, return redirect 해줘서 list로 이동함

 

@PostMapping("/register")
    public String  registerPost(TodoDTO todoDTO){
        log.info("post todo register ....");
        log.info(todoDTO);

        return "redirect:/todo/list";
    }

 

 

UTF-8 필터 처리

 

web.xml 추가

<filter>
        <filter-name>encoding</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>encoding</filter-name>
        <servlet-name>appServlet</servlet-name>
    </filter-mapping>

 

 

@Valid를 이용한 서버사이드 검증

 

build.gradle 추가

 //Validate 관련 라이브러리
  implementation group: 'org.hibernate', name : 'hibernate-validator' , version : '6.2.1.Final'

 

 

dto

 

@Builder
@Data // 오버라이딩할 수있는 getter setter toString hashocode ~~  몽땅 세팅
@NoArgsConstructor
@AllArgsConstructor
@Setter
public class TodoDTO {
    private Long tno;
    @NotEmpty
    private String title;
    @Future
    private LocalDate dueDate;
    private boolean finished;
    @NotEmpty
    private String writer;
}

 

 

controller

 

@PostMapping("/register")
    public String  registerPost(@Valid TodoDTO todoDTO, BindingResult bindingResult, RedirectAttributes redirectAttributes){
        log.info("post todo register ....");

        if(bindingResult.hasErrors()){
            log.info("has errors....");
            redirectAttributes.addFlashAttribute("errors",bindingResult.getAllErrors());
            return "redirect:/todo/register";
        }

        log.info(todoDTO);

        // 문제가 발생안하면 list로
        return "redirect:/todo/list";
    }

 

 

@NotEmpty인 writer 을 안썼다. 내용 다 안담으면 에러 나면서 레지스터로 감

 

 

아무것도 안쓰면 콘솔에 이렇게 뜸

 

 

TodoService 를 TodoConroller에 주입

 

@RequiredArgsConstructor
public class TodoController {
    
    private final TodoService todoService;

 

 

추가

 

todoService.register(todoDTO);

 

 

 

 

 

 

의존성 주입 == 객체 new로 생성하는걸 스킵하는것
그럼 누가 new를 해주는가 == 스프링 컨테이너에서 해준다
스프링컨테이너는 어떻게 알고 생성해주는가 == 스프링(빈) 컨테이너에 등록된 컴포넌트를 확인한다
컴포넌트는 어떻게 확인하는가 == 컴포넌트 스캔을 한다
컴포넌트스캔은 어떻게하는가 == root.context.xml 같은데서 작성한다

 

설렉트

 

TodoMapper interface

List<TodoVO> selectAll();

 

todomapper.xml


쿼리문

<select id="selectAll" resultType="com.ssg.todo.domain.TodoVO">
        select * from tbl_todo order by tno desc
    </select>

 

 

test

@Test
    public void testSelectAll(){

        List<TodoVO> list = todoMapper.selectAll();
        list.forEach(vo->log.info(vo));

    }

 

 

TodoService

 

List<TodoDTO> getAll();

 

 

TodoServiceimpl

 

@Override
    public List<TodoDTO> getAll(){

        List<TodoDTO> dtoList = todoMapper.selectAll().stream()
                .map(vo->modelMapper.map(vo,TodoDTO.class))
                .collect(Collectors.toList());


        return dtoList;
    }

 

 

controller

 

전달할 model 추가, dtoList라는 이름으로 속성 추가.

 

@RequestMapping("/list") // /todo/list로 요청
    public void list(Model model){ //model 추가
        log.info("todo list........")    ;
        
        model.addAttribute("dtoList",todoService.getAll());
        //model 객체에 담아서 보냄
    }

 

 

jsp

 

뷰에서 dtoList로 받는다.

 

<tbody>
<c:forEach items="${dtoList}" var="dto">

<tr>
<th scope="row"><c:out value="${dto.tno}"/></th>
<td>
<a href="/todo/read?tno=${dto.tno}&${pageRequestDTO.link}" class="text-decoration-none" data-tno="${dto.tno}" >
<c:out value="${dto.title}"/>
</a>
</td>
<td><c:out value="${dto.writer}"/></td>
<td><c:out value="${dto.dueDate}"/></td>
<td><c:out value="${dto.finished}"/></td>
</tr>
</c:forEach>


                            </tbody>

 

 

/todo/list

 

 

 

힌개 가져오기

 

TodoMapper.interface

 

TodoVO selectOne(Long tno);

 

 

TodoMapper.xml

 

받은 tno 사용

 

<mapper namespace=“com.ssg.springex.mapper.TodoMapper">

<select id="selectOne" resultType=“com.ssg.springex.domain.TodoVO">
select * from tbl_todo where tno = #{tno}
</select>
</mapper>

 

 

TodoService

 

TodoDTO getOne(Long tno);

 

 

 

TodoServiceimpl

 

@Override
public TodoDTO getOne(Long tno) {
TodoVO todoVO = todoMapper.selectOne(tno);
TodoDTO todoDTO = modelMapper.map(todoVO, TodoDTO.class);
return todoDTO;
}

 

 

controller


todoVO라는 이름으로 모델에 담아서 보낸다.

 

@GetMapping("/read")
public void read(Long tno, Model model){
TodoDTO todoDTO = todoService.getOne(tno);
log.info(todoDTO);
model.addAttribute("dto", todoDTO);
}

 

 

 

 

.jsp

 

버튼누르면 "click"이벤트 발생 , function 안에 핸들러 정의
modify 서블릿을 불러라! /todo/modify?tno=${dto.tno}

 

.
.
<input type="text" name="tno" class="form-control"
                                   value=<c:out value="${dto.tno}"></c:out> readonly>
.
.
//버튼
<button type="button" class="btn btn-primary">Modify</button>
<button type="button" class="btn btn-secondary">List</button>
.
.

document.querySelector(".btn-primary").addEventListener("click", function(e){
                                self.location = "/todo/modify?tno="+${dto.tno}
                            },false)
                            
document.querySelector(".btn-secondary").addEventListener("click", function(e){
                                self.location = "/todo/list";
                            },false)

 

@GetMapping에 read, modify 같이 쓰게 해놓음, 요청을 같이쓰겠다

 

@GetMapping ({"/read", "/modify"}) // 배열처럼
    public void read(Long tno, Model model){
        TodoDTO todoDTO = todoService.getOne(tno);
        log.info(todoDTO);
        model.addAttribute("dto", todoDTO);
    }

 

 

삭제

 

TodoMapper interface

 

void delete(Long tno);

 

 

TodoMapper.xml

 

<mapper
namespace=“com.ssg.springex.mapper.TodoMapper">
...
<delete id="delete">
delete from tbl_todo where tno = #{tno}
</delete>
</mapper>

 

 

TodoService

 

void remove(Long tno);

 

 

TodoServiceimpl

 

@Override
public void remove(Long tno) {
todoMapper.delete(tno);
}

 

 

Controller

 

@PostMapping("/remove")
public String remove(Long tno, RedirectAttributes redirectAttributes){
log.info("-------------remove------------------");
log.info("tno: " + tno);
return "redirect:/todo/list";
}

 

 

.jsp

 

//버튼
<button type="button" class="btn btn-danger">Remove</button>
.
.
.

document.querySelector(".btn-danger").addEventListener("click",function(e) {

e.preventDefault()
e.stopPropagation()

formObj.action =`/todo/remove?${pageRequestDTO.link}`
formObj.method ="post"

formObj.submit()

},false);

 

 

수정

 

TodoMapper interface

 

void update(TodoVO todoVO);

 

 

TodoMapper.xml

 

<update id="update">
update tbl_todo set title = #{title} , dueDate = #{dueDate},
finished= #{finished} where tno = #{tno}
</update>

 

 

TodoService

 

void modify(TodoDTO todoDTO);

 

 

TodoServiceImpl

 

@Override
public void modify(TodoDTO todoDTO) {
TodoVO todoVO = modelMapper.map(todoDTO, TodoVO.class );
todoMapper.update(todoVO);
}

 

 

checkbox를 위한 Formatter

on 이라는 값으로 넘어오는걸 불린값으로 변경

 

package com.ssg.springex.controller.formatter;
import org.springframework.format.Formatter;
import java.text.ParseException;
import java.util.Locale;
public class CheckboxFormatter implements Formatter<Boolean> {
@Override
public Boolean parse(String text, Locale locale) throws ParseException {
if(text == null ) {
return false;
}
return text.equals("on");
}
@Override
public String print(Boolean object, Locale locale) {
return object.toString();
}
}

 

++


sevelet-context.xml 추가

 

<bean id="conversionService" class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
<property name="formatters">
<set>
<bean class=“com.ssg.springex.controller.formatter.LocalDateFormatter"/>
<bean class="com.ssg.springex.controller.formatter.CheckboxFormatter"/>
</set>
</property>
</bean>

 

 

TodoController

 

@PostMapping("/modify")
public String modify(@Valid TodoDTO todoDTO,
BindingResult bindingResult,
RedirectAttributes redirectAttributes){
if(bindingResult.hasErrors()) {
log.info("has errors.......");
redirectAttributes.addFlashAttribute("errors", bindingResult.getAllErrors() );
redirectAttributes.addAttribute("tno", todoDTO.getTno() );
return "redirect:/todo/modify";
}
log.info(todoDTO);
todoService.modify(todoDTO);
return "redirect:/todo/list";
}
반응형