20220511 복습

2022 - 0511 - 복습


package com.jslhrd.sample;

import org.springframework.stereotype.Component;

import lombok.Data;

@Component //스프링에게 해당 클래스가 스프링에서 관리해야 하는 대상임을 표시
@Data //Lombok(setter,생성자,toString()등)을 자동 생성하는 어노테이션
public class Chef {
     
}


package com.jslhrd.sample;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import lombok.Data;
import lombok.Setter;

@Component //스프링에게 해당 클래스가 스프링에서 관리해야 하는 대상임을 표시
@Data //Lombok(setter,생성자,toString()등)을 자동 생성하는 어노테이션
public class Restaurant {

     @Setter(onMethod_ = @Autowired) // 의존성
     private Chef chef;
}


package com.jslhrd.sample;

import static org.junit.Assert.assertNotNull;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import lombok.Setter;
import lombok.extern.log4j.Log4j;

@RunWith(SpringJUnit4ClassRunner.class) //현재 테스트 코드가 스프링을 실행하는 역할을 할 것이다.
@ContextConfiguration("file:src/main/webapp/WEB-INF/spring/root-context.xml") //필요한 객체들을 스프링 내에 객체로 등록(Spring's Bean)
@Log4j //Lombok을 이용하여 로그기록하는 Logger를 변수로 생성.
public class SampleTests {

     @Setter(onMethod_ = @Autowired) //@Autowired = 해당 인스턴스 변수가 스프링으로부터 자동으로 주입해 달라는 표시.
     private Restaurant restaurant;

     @Test
     public void testExist() {

          assertNotNull(restaurant); //restaurant변수가 null이 아니어야만 테스트가 성공한다는 뜻.

          log.info(restaurant);
          log.info("------------------");
          log.info(restaurant.getChef());
     }
}


package com.jslhrd.persistence;

import static org.junit.Assert.fail;
import java.sql.Connection;
import java.sql.DriverManager;

import org.junit.Test;

import lombok.extern.log4j.Log4j;

@Log4j
public class JDBCTests {

     static {
          try {
               Class.forName("oracle.jdbc.driver.OracleDriver");
          } catch (Exception e) {
               e.printStackTrace();
          }
     }

     @Test
     public void testConnection() {
          try {
               Connection con = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:XE","system","123456");
               log.info(con);
               log.info("성공");
               Class.forName("oracle.jdbc.driver.OracleDriver");
          } catch (Exception e) {
               log.info("실패");
               e.printStackTrace(); //
               fail(e.getMessage());
          }
     }

}


import static org.junit.Assert.fail;

import java.sql.Connection;

import javax.sql.DataSource;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import lombok.Setter;
import lombok.extern.log4j.Log4j;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("file:src/main/webapp/WEB-INF/spring/root-context.xml")
@Log4j
public class DataSourceTests {

     @Setter(onMethod_ = @Autowired)
     private DataSource ds;

     @Test
     public void testConnection(){

          try(Connection con = ds.getConnection()) {

               log.info(con);
               log.info("success!!!");

          } catch (Exception e) {
               e.printStackTrace();
               fail(e.getMessage());
          }
     }
}


package com.jslhrd.domain;

import java.sql.Date;

import lombok.Data;

@Data
//Lombok(setter,생성자,toString()등)을 자동 생성하는 어노테이션
public class BoardVO {

     private long bno;
     private String title;
     private String content;
     private String writer;
     private Long hit;
     private Date regdate;
     private Date updatedate;
}


package com.jslhrd.mapper;
import java.util.List;
import com.jslhrd.domain.BoardVO;

public interface BoardMapper {

     public List<BoardVO> getList();

     public void insert(BoardVO board);

     public void insertSelectKey(BoardVO board);

     public BoardVO read(Long bno);

     public int update(BoardVO board);

     public int delete(Long bno);

}


package com.jslhrd.mapper;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.jslhrd.domain.BoardVO;

import lombok.Setter;
import lombok.extern.log4j.Log4j;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("file:src/main/webapp/WEB-INF/spring/root-context.xml")
@Log4j
public class BoardMapperTests {

     @Setter(onMethod_ = @Autowired)
     private BoardMapper mapper;

     @Test
     public void testGetList() {
          mapper.getList().forEach(board -> log.info(board));
     }

     @Test
     public void testInsert() {
          BoardVO board = new BoardVO();
           board.setTitle("insert");
          board.setContent("insert");
           board.setWriter("insert");
          mapper.insert(board);
           log.info("-------------------insert result-----------------------");
          log.info(board);
          log.info("------------------------------------------");
     }

     @Test
     public void testInsertSelectKey() {
          BoardVO board = new BoardVO();
          board.setTitle("insert K");
          board.setContent("insert K");
          board.setWriter("insert K");
          mapper.insertSelectKey(board);
          log.info("-------------------insert Select Key result-----------------------");
          log.info(board);
          log.info("------------------------------------------");
     }

     @Test
     public void testRead() {
          BoardVO board = mapper.read(16L);
          log.info("-------------------read result-----------------------");
          log.info(board);
          log.info("------------------------------------------");
     }

     @Test
     public void testUpdate() {
          BoardVO board = new BoardVO();
          board.setBno(16L);
          board.setTitle("update");
          board.setContent("update");
          board.setWriter("update");
          log.info("UPDATE RESULT !!! : " + mapper.update(board));

     }
     @Test
     public void testDelete() {
          int count = mapper.delete(31L);
          log.info("DELETE RESULT !!! : "+count);
     }


}


package com.jslhrd.service;
import java.util.List;
import com.jslhrd.domain.BoardVO;
public interface BoardService {

     public List<BoardVO> getList();

     public BoardVO get(Long bno);

     public void insert(BoardVO board);

     public boolean update(BoardVO board);

     public boolean delete(Long bno);

}


package com.jslhrd.service;
import java.util.List;
import org.springframework.stereotype.Service;
import com.jslhrd.domain.BoardVO;
import com.jslhrd.mapper.BoardMapper;
import lombok.AllArgsConstructor;
import lombok.extern.log4j.Log4j;

@Service // 계층 구조상 주로 비즈니스 영역을 담당하는 객체임을 표시하기 위해 사용함.
@Log4j
@AllArgsConstructor // 생성자를 만들고 자동으로 주입함. (생성자를 만들지 않을 경우에는 @setter()를 이용해서 처리함)
public class BoardServiceImpl implements BoardService{

     // @Setter(onMethod_ = @Autowired)
     private BoardMapper mapper;

     @Override
     public List<BoardVO> getList(){
          log.info("GET LIST ----------------------------");
          return mapper.getList();
     }

     @Override
     public BoardVO get(Long bno) {
          log.info("GET : " + bno);
          return mapper.read(bno);
     }

     @Override
     public void insert(BoardVO board) {
          log.info("INSERT : " + board);
          mapper.insertSelectKey(board);
     }

     @Override
     public boolean update(BoardVO board) {
          log.info("UPDATE : " + board);
          return mapper.update(board) == 1;
     }

     @Override
     public boolean delete(Long bno) {
          log.info("DELETE : " + bno);
          return mapper.delete(bno) == 1;
     }

}


package com.jslhrd.service;

import static org.junit.Assert.assertNotNull;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import com.jslhrd.domain.BoardVO;
import lombok.Setter;
import lombok.extern.log4j.Log4j;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("file:src/main/webapp/WEB-INF/spring/root-context.xml")
@Log4j
public class BoardServiceTests {

     @Setter(onMethod_ = @Autowired)
     private BoardService service;

     @Test
     public void testExist() {
          log.info(service);
          assertNotNull(service);
     }

     @Test
     public void testGetList() {
          service.getList().forEach(board -> log.info(board));
     }

     @Test
     public void testGet() {
          log.info("GET ---------------------------------------");
          log.info(service.get(17L));
     }
     @Test
     public void testInsert() {
          log.info("INSERT --------------------------------------");
          BoardVO board = new BoardVO();
          board.setTitle("insert");
          board.setContent("insert");
          board.setWriter("insert");
          service.insert(board);
     }

     @Test
     public void testUpdate() {
          BoardVO board = service.get(17L);
          if(board == null) {
               return;
          }
          board.setTitle("update");
          board.setContent("update");
          board.setWriter("update");
          log.info("UPDATE RESULT : " + service.update(board));
     }

     @Test
     public void testDelete() {
          log.info("DELETE RESULT : " + service.delete(30L));
     }

}


package com.jslhrd.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import com.jslhrd.domain.BoardVO;
import com.jslhrd.service.BoardService;

import lombok.AllArgsConstructor;
import lombok.extern.log4j.Log4j;

@Controller //스프링의 빈으로 인식할 수 있게 함.
@Log4j
@RequestMapping("/board/*") //'/board'로 시작하는 모든 처리를 BoardController가 하도록 지정.
@AllArgsConstructor
public class BoardController {

     private BoardService service;

     @GetMapping("/list")
     public void list(Model model) {
          log.info("list --------------------------------------------------");
          model.addAttribute("list",service.getList());
     }

     @GetMapping("/insert")
     public void insert() {

     }

     @PostMapping("/insert") //새롭게 등록된 게시물의 번호를 같이 전달(RedirectAttributes)
     public String insert(BoardVO board, RedirectAttributes rttr) {
          log.info("INSERT : " + board);
          service.insert(board);
          rttr.addFlashAttribute("result", board.getBno());
          return "redirect:/board/list";
     }

     @GetMapping("/get") //bno를 좀 더 명시적으로 처리(@RequestParam), 화면쪽으로 게시물 전달(Model)
     public void get(@RequestParam("bno") Long bno, Model model) {
          log.info("get --------------------------------------------------");
          model.addAttribute("board",service.get(bno));
     }

     @PostMapping("/update")
     public String update(BoardVO board, RedirectAttributes rttr) {
          log.info("update --------------------------------------------------");
          if(service.update(board)) {
               rttr.addFlashAttribute("result", "update_success");
          }
          return "redirect:/board/list";
     }

     @PostMapping("/delete")
     public String delete(@RequestParam("bno") Long bno, RedirectAttributes rttr) {
          log.info("delete --------------------------------------------------");
          if(service.delete(bno)) {
               rttr.addFlashAttribute("result","delete_success");
          }
          return "redirect:/board/list";
     }


}


package com.jslhrd.controller;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;

import lombok.Setter;
import lombok.extern.log4j.Log4j;

@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration //Servlet의 ServletContext 이용. 스프링에서는 WebApplicationContext라는 존재를 이용.
@ContextConfiguration({"file:src/main/webapp/WEB-INF/spring/root-context.xml",
"file:src/main/webapp/WEB-INF/spring/appServlet/servlet-context.xml"})
@Log4j
public class BoardControllerTests {

     @Setter(onMethod_ = @Autowired)
     private WebApplicationContext ctx;
     private MockMvc mockMvc;

     @Before //@Before가 적용된 메서드는 모든 테스트 전에 매번 실행되는 메서드.
     public void setup() {
          this.mockMvc = MockMvcBuilders.webAppContextSetup(ctx).build();
     } // MockMvc = 가짜 MVC (URL,파라미터 등을 가짜로 브라우저에서 사용하는 것처럼 하여 Controller를 실행 가능.)
     @Test
     public void testList() throws Exception {
          log.info("test");
          log.info(
               mockMvc.perform(MockMvcRequestBuilders.get("/board/list"))
                    .andReturn()
                    .getModelAndView()
                    .getModelMap()
          );
     }

     @Test
     public void testInsert() throws Exception {
          log.info("INSERT----------------------------------------------");
          String resultPage = mockMvc.perform(MockMvcRequestBuilders.post("/board/insert")
               .param("title","test new")
               .param("content","test new")
               .param("writer","test new")
               ).andReturn().getModelAndView().getViewName();

          log.info(resultPage);
     }

     @Test
     public void testGet() throws Exception {
          log.info("GET----------------------------------------------");
          mockMvc.perform(MockMvcRequestBuilders.get("/board/get")
               .param("bno","36")
               ).andReturn().getModelAndView().getViewName();
     }

     @Test
     public void testUpdate() throws Exception {
          log.info("UPDATE----------------------------------------------");
          String resultPage = mockMvc.perform(MockMvcRequestBuilders.post("/board/update")
               .param("bno","34")
               .param("title","new update")
               .param("content","new update")
               .param("writer","new update")
               ).andReturn().getModelAndView().getViewName();
          log.info(resultPage);
     }

     @Test
     public void testDelete() throws Exception {
          log.info("DELETE----------------------------------------------");
          String resultPage = mockMvc.perform(MockMvcRequestBuilders.post("/board/delete")
               .param("bno","33")
               ).andReturn().getModelAndView().getViewName();
          log.info(resultPage);
     }


}


< Spring 기초 >




>>> pom.xml
12라인 -> 5.0.7
64라인 -> 1.2.17
116라인 -> 4.12
139라인 -> 3.5.1
141라인 -> 1.8
142라인 -> 1.8
-----------------------------------------------------------------------------------------------------
>>> root-context.xml

<bean id="hikariConfig" class="com.zaxxer.hikari.HikariConfig">

     <property name="driverClassName"
          value="net.sf.log4jdbc.sql.jdbcapi.DriverSpy"></property>
     <property name="jdbcUrl"
          value="jdbc:log4jdbc:oracle:thin:@localhost:1521:XE"></property>
     <property name="username" value="db53"></property>
     <property name="password" value="123456"></property>

</bean>

<!-- HikariCP configuration -->
<bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource"
     destroy-method="close">
          <constructor-arg ref="hikariConfig" />
</bean>

<bean id="sqlSessionFactory"
     class="org.mybatis.spring.SqlSessionFactoryBean">
          <property name="dataSource" ref="dataSource">
</bean>

<mybatis-spring:scan
     base-package="com.jslhrd.mapper" />

<context:component-scan
     base-package="com.jslhrd.service">

-----------------------------------------------------------------------------------------------------
>>> buildpath
mysql-connector-java-8.0.28.jar
ojdbc8.jar
-----------------------------------------------------------------------------------------------------
>>>src/main/resources
log4jdbc.log4j2.properties 파일 생성
log4jdbc.spylogdelegator.name=net.sf.log4jdbc.log.slf4j.Slf4jSpyLogDelegator 내용입력
-----------------------------------------------------------------------------------------------------
>>>
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("file:src/main/webapp/WEB-INF/spring/root-context.xml")
@Log4j

@Setter(onMethod_ = @Autowired)
@Select("select sysdate from dual")

@Service // 계층 구조상 주로 비즈니스 영역을 담당하는 객체임을 표시하기 위해 사용함.
@Log4j
@AllArgsConstructor // 생성자를 만들고 자동으로 주입함.

<BoardController.java>
@Controller
@Log4j
@RequestMapping("/board/*")
@AllArgsConstructor

<BoardControllerTests.java>
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration({"file:src/main/webapp/WEB-INF/spring/root-context.xml",
               "file:src/main/webapp/WEB-INF/spring/appServlet/servlet-context.xml"})
@Log4j

>>>Tomcat 더블클릭 - Modules - Edit - controller 부분 지우기
-----------------------------------------------------------------------------------------------------
P.173
>>>Oracle 테이블

사용자 추가 후

system/123456

db53/123456


create user db53 identified by 123456;
grant connect,resource to db53;
grant create view to db53;

create sequence seq_board;

create table tbl_board(
bno number(10,0),
title varchar2(200) not null,
content varchar2(2000) not null,
writer varchar2(50) not null,
regdate date default sysdate,
updatedate date default sysdate
);

alter table tbl_board add constraint pk_board primary key(bno);

insert into tbl_board(bno,title,content,writer) values(seq_board.nextval,'테스트 제목','테스트 내용','user00');
insert into tbl_board(bno,title,content,writer) values(seq_board.nextval,'테스트 제목','테스트 내용','user01');
insert into tbl_board(bno,title,content,writer) values(seq_board.nextval,'테스트 제목','테스트 내용','user02');
insert into tbl_board(bno,title,content,writer) values(seq_board.nextval,'테스트 제목','테스트 내용','user03');
insert into tbl_board(bno,title,content,writer) values(seq_board.nextval,'테스트 제목','테스트 내용','user04');
insert into tbl_board(bno,title,content,writer) values(seq_board.nextval,'테스트 제목','테스트 내용','user05');
insert into tbl_board(bno,title,content,writer) values(seq_board.nextval,'테스트 제목','테스트 내용','user06');
insert into tbl_board(bno,title,content,writer) values(seq_board.nextval,'테스트 제목','테스트 내용','user07');
insert into tbl_board(bno,title,content,writer) values(seq_board.nextval,'테스트 제목','테스트 내용','user08');
insert into tbl_board(bno,title,content,writer) values(seq_board.nextval,'테스트 제목','테스트 내용','user09');
insert into tbl_board(bno,title,content,writer) values(seq_board.nextval,'테스트 제목','테스트 내용','user10');

-----------------------------------------------------------------------------------------------------
>>> BoardMapper.xml (@Select 어노테이션을 써도 되지만, 쿼리문이 복잡해질 경우 xml 파일로 관리하는게 유리하다 !!!)

src/main/resources -> com 폴더 -> jslhrd 폴더 -> mapper 폴더 생성 후, 그 안에 BoardMapper.xml 파일 생성
(com.jslhrd.mapper 패키지 명과 동일한 틀로)

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
     PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
     "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.jslhrd.mapper.BoardMapper">

     <!-- 부등호 들어가면 CDATA 처리 !!! -->

     <select id="getList" resultType="com.jslhrd.domain.BoardVO">
          <![CDATA[
               select * from tbl_board where bno > 0
          ]]>
     </select>

     <insert id="insert">
          insert into tbl_board(bno,title,content,writer) values(seq_board.nextval, #{title}, #{content}, #{writer})
     </insert>

     <insert id="insertSelectKey">
          <selectKey keyProperty="bno" order="BEFORE" resultType="long">
               select seq_board.nextval from dual
          </selectKey>
          insert into tbl_board(bno,title,content,writer) values(#{bno}, #{title}, #{content}, #{writer})
     </insert>

     <select id="read" resultType="com.jslhrd.domain.BoardVO">
          select * from tbl_board where bno = #{bno}
     </select>

     <update id="update">
          update tbl_board
          set title=#{title},
          content=#{content},
          writer=#{writer},
           updateDate=sysdate
          where bno=#{bno}
     </update>

     <delete id="delete">
          delete from tbl_board where bno=#{bno}
     </delete>

</mapper>

-----------------------------------------------------------------------------------------------------
src/main/resources -> com 폴더 -> jslhrd 폴더 -> mapper 폴더 생성 후, 그 안에 TimeMapper.xml 파일 생성
(com.jslhrd.mapper 패키지 명과 동일한 틀로)

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
     PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
     "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.jslhrd.mapper.TimeMapper">
     <select id="getTime2" resultType="string">
          select sysdate from dual
     </select>
</mapper>


https://mvnrepository.com/ <- dependency 검색
https://start.spring.io/ <- Spring Start Page

- 세팅이 반이다 !
- Test 중요 !
- build path (mysql-connector-java-8.0.28.jar , ojdbc8.jar)
- pom.xml 계속 수정

MVC

   (Model View Controller)

   Presentation - Client의 요청을 받아 Business에게 처리를 전달.
   Business - 실제 요청에 대한 처리를 담당. (Service)
   Persistence - Business의 처리에 따라 데이터베이스에 접근. 저장,조회,삭제 등 수행.

Layered Architecture


   각 계층은 자신의 계층이 갖는 책임에만 충실하도록 개발해야 한다.

View

Model Model

Presentation
@Controller

Model Model

Business
@Service

DTO Model

Persistence

DTO Model

DB
(Oracle)



프레젠테이션(웹) 계층의 CRUD 구현
Task URL Method Parameter From URL 이동
전체 목록 /board/list GET x x x
등록 처리 /board/insert POST 모든 항목 입력화면 필요 이동
조회 /board/get GET bno x x
수정 처리 /board/update POST 모든 항목 입력화면 필요 이동
삭제 목록 /board/delete POST bno 입력화면 필요 이동

Presentation

   @Controller
   프레젠테이션 계층에서는 클라이언트로부터 HTTP 요청을 수신하고 그에 맞는 응답을 돌려주는 계층이다.
   프레젠테이션 계층에서는 어떠한 요청을 받고, 어떠한 응답 상태와 데이터를 반환하는지에 대한 책임이 있다.
   웹 개발 시, 매번 URL을 테스트하기 위해서 Tomcat(WAS)을 실행하는 불편한 단계를 생략
   가짜 MVC인 MockMvc를 이용하여 URL,파라미터 등을 브라우저에서 사용하는 것처럼 만들어서 Controller를 실행 가능.
   귀찮아서 Controller에 대한 테스트 코드를 작성하지 않는 경우가 많지만, WAS의 재시작 시간 등을 고려해보면
   테스트를 진행하는 것이 훨씬 더 빠른 개발의 결과를 낳는 경우가 많으니 테스트를 먼저 진행하는 습관이 중요.

Service

   @Service
   서비스 계층에서는 요구 사항에 맞게 비지니스 로직을 작성하는 계층이다.
   그렇기 때문에 일반적으로 서비스의 핵심 로직들이 주로 담겨 있다.
   또한 트랜잭션에 대한 관리 역시 서비스 계층에서 처리하는 것이 일반적인 패턴이다.

Persistence

   퍼시스턴스 계층은 데이터 처리를 담당하는 계층이다.
   주로 데이터의 생성/수정/삭제/선택(검색)과 같은 CRUD 연산을 수행하게 된다.


상위 폴더 패키지 클래스




src/main/java
com.jslhrd.sample Chef.java
Restaurant.java
com.jslhrd.controller BoardController.java (C)(Pre)
HomeController.java
com.jslhrd.mapper BoardMapper.java (I)(Per)
TimeMapper.java
com.jslhrd.domain BoardVO.java (C)(Per)
com.jslhrd.service BoardService.java (I)(Ser)
BoardServiceImpl.java (C)(Ser)




src/test/java
com.jslhrd.sample SmapleTests.java
com.jslhrd.controller BoardControllerTests.java (C)(Pre)

com.jslhrd.persistence
DataSourceTests.java
JDBCTests.java
TimeMapperTests.java
com.jslhrd.mapper BoardMapperTests.java (C)(Per)
com.jslhrd.service BoardServiceTests.java (C)(Ser)

src/main/resources
com/jslhrd/mapper BoardMapper.xml
TimeMapper.xml
. log4jdbc.log4j2.properties

webapp/WEB-INF/views
board list.jsp
insert.jsp
includes headr.jsp
footer.jsp

tbl_board
필드명 타입 설명
BNO NUMBER(10) 게시글 번호
TITLE VARCHAR(200) 제목
CONTENT VARCHAR(2000) 내용
WRITER VARCHAR(50) 작성자
HIT NUMBER(10) 조회수
REGDATE DATE 작성일
UPDATEDATE DATE 수정일