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";
}
'신세계 - Spring 공부' 카테고리의 다른 글
16주차 배운점 - 스프링 부트, ORM, 하이버네이트 (1) | 2024.09.24 |
---|---|
15주차 배운점 - Spring mybatis Todo 프로그램 (테이블 페이징) (0) | 2024.09.24 |
15주차 배운점 - 퍼사드 패턴, 컨트롤러, Formatter, 예외처리, Mapper (0) | 2024.09.24 |
15주차 배운점 - 스프링, MyBatis, 스프링 Web MVC (2) | 2024.09.23 |
14주차 배운점 - Session, 쿠키, 필터 (1) | 2024.09.23 |