공부/그룹 스터디

[6회차 01] 게시판 리스트 만들기 - DB값 넣기, 의존성 주입

junani0v0 2024. 5. 10. 22:49

[6회차] 게시판 리스트 만들기

10_board_01-develop.zip

properties

위 파일을 다운로드 하셔서 import해줍니다
import후 properties -> Project Facets -> Java버전을 11로 바꿔줍니다 -> Apply

Java Build Path에 Server Runtime가 없다면 Targeted Runtimes에가서 톰캣을 선택해줍니다

pom.xml

maven-compiler-pluginrelease도 11로 변경

jakarta.servlet은 원래 javax.servlet인데 이름이 jakarta로 바뀐겁니다

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://xmlns.jcp.org/xml/ns/javaee"
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
    id="WebApp_ID" version="4.0">
    <display-name>10_board_01</display-name>
    <!-- Spring configuration start -->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>

    <!-- 루트 어플리케이션컨텍스트 영역 -->
    <!-- 시작점을 의미 한다 -->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath*:/context*.xml</param-value>
    </context-param>
    <!-- Spring configuration end -->

    <!-- 한글 처리를 위한 필터 설정 -->
    <filter>
        <filter-name>encodingFilter</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>
        <init-param>
            <param-name>forceEncoding</param-name>
            <param-value>true</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>encodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    <!-- 한글 처리를 위한 필터 설정 끝 -->

    <!-- Spring servlet start -->
    <servlet>
        <servlet-name>pf</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>pf</servlet-name>
        <url-pattern>*.do</url-pattern>
    </servlet-mapping>

    <welcome-file-list>
        <welcome-file>index.html</welcome-file>
        <welcome-file>index.htm</welcome-file>
        <welcome-file>index.jsp</welcome-file>
        <welcome-file>default.html</welcome-file>
        <welcome-file>default.htm</welcome-file>
        <welcome-file>default.jsp</welcome-file>
    </welcome-file-list>
</web-app>

ContextLoaderListener가 있고 그 설정파일은

<!-- 루트 어플리케이션컨텍스트 영역 -->
<!-- 시작점을 의미 한다 -->
<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath*:/context*.xml</param-value>
</context-param>
<!-- Spring configuration end -->

이렇게 되어있습니다
그다음 필터가 있고 서블릿 맵핑이있습니다

그리고 제일 중요한 것은

<servlet-mapping>
    <servlet-name>pf</servlet-name>
    <url-pattern>*.do</url-pattern>
</servlet-mapping>

servlet-mappingurl-pattern을 꼭 확인합니다 이 패턴은 한가지가 아니고 여러가지 일 수도 있기에 시작전에 확인해주세요

pf-servlet.xml

<context:component-scan base-package="com.pf.www" use-default-filters="false">
    <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller" />
    <context:include-filter type="annotation" expression="org.springframework.stereotype.Component" />
</context:component-scan>

베이스 패키지를 확인해줍니다

<bean
    class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="prefix" value="/WEB-INF/views/" />
    <property name="suffix" value=".jsp" />
    <property name="order" value="2" />
</bean>

ViewResolver 가 있으면 jsp경로를 설정해줍니다

<mvc:resources mapping="/assest/**" location="/assest/" />

그리고 마지막으로 mvc:resources mapping을 확인합니다(js나 css등등 경로 지정)

NoticeController

@RequestMapping("/forum//notice/listPage.do")
public ModelAndView listPage(@RequestParam HashMap<String, String> params) {
    ModelAndView mv = new ModelAndView();
    mv.addObject("key", Calendar.getInstance().getTimeInMillis());
    mv.setViewName("forum/notice/list");

    return mv;
}

index.html에 보면 처음 연결되는 페이지가 /10/forum//notice/listPage.do입니다 그러면 listPage.do는 list.jsp와 연결되는데 연결이 잘되었나 확인해 보겠습니다

list.jsp


이렇게 body위에 ${key}값을 찍어 controller에서 값이 넘어오는지 확인합니다


서버를 실행해 확인해보면 죄측 상단이 이렇게 key값이 나옵니다

context-database.xml 생성

현재 DB와 연결해주는게 아무것도 없기에 DB연결을 위해 src/main/resources/context-database.xml을 만들어 줍니다

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans-4.1.xsd">

    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver" />
        <property name="url" value="jdbc:mysql://localhost:53306/forum?serverTimezone=Asia/Seoul" />
        <property name="username" value="root"/>
        <property name="password" value="admin_123"/>
    </bean>

</beans>

하고 서버를 돌린뒤 console에서 ctrl + fdataSource 검색


검색이 된다면 잘등록된 것입니다

DB


board의 엔티티 관계도를 보면 동그라미가 있는 쪽이 N입니다

그다음 이제 board_type으로가서


게시판을 만들어줍니다
예을들어 가입인사, 공지사항, 자유게시판 등등을 테이블로 전부 많드는게 아닌 위처럼 하나의 테이블에 타입을 만들어 사용합니다
일단 현재 사용할 게시판을 하나 만들어줍니다 저는 memo페이지를 만들었습니다 그리고 사용여부를 'Y'로하고 생성일시를 적어줍니다


아래 SAVE옆 삼각형을 누르면 스크랩트 생성이 나오는데 이걸 클릭하면


이 처럼 쿼리문을 확인할 수 있습니다

이렇게하면 이제 어디에 글을 쓸지는 준비가 된것입니다

ERD 설명

  • 식별관계(실선) : 관계설정이 무조건 존재해야됨, 객체에 연결된 정보가 고유의 정보면 식별
    (ex.개인정보 )( 주민등록번호는 비식별일 수 없음, 탈퇴하면 리뷰,구매내역 등등 기록 다지워야됨 - 식별관계이기 때문)
  • 비식별관계(점선) : 소유물, 상품
    소유물 잃어버리면 비식별
    ex.물건을 잃어버려 비식별이됨

DB 게시글 추가

이제 list보여주기를 할껀데요 그러기 위해선 DB에 값을 넣어줘야하는데요 페이징을 하기위해서는 많은 양을 넣어야하기에 다른 사이트를 사용해 넣겠습니다(페이징 30개 이상 만들어야됩니다)

임의 데이터 생성

  • Mock Data
  • Generate Data

중 하나를 사용하겠습니다


저는 Mock Data를 사용해 만들었습니다

  • board_type_seq : 아까 만든 게시판 번호를 입력하시면 됩니다 저희는 1번으로만 할 것이기에 min과 max에 1을 넣어줍니다
  • title : type Catch Phrase로 해줍니다
  • content : type words 로하고 10~50개로 해서 많은 내용이 담기게 했습니다
  • rows : 1000개를 만들었으며 SQL을 선택후 테이블 이름을 입력

화면 캡처 2024-05-10 210644

생성하면 이렇게 preview가 나오고 `generate data`를 클릭하면 파일이 하나 다운로드 됩니다 이걸 메모장으로 열러 전체 복사하여 SQL편집기를 열고 붙여넣기 후 insert문을 전부 실행(Alt+X)해주면 테이블에 값이 들어옵니다


혹시 이런 에러가 발생했다면


값을 넣으려는 DB를 우클릭하고 Set as default를 클릭해주고 다시 실행하세요

BoardDto 생성

이제까지 Dto는 하나의 테이블만 사용하는 Dto를 만들었었는데요
오늘은 관계성 테이블이기때문에 join으로 여러 테이블의 값을 사용합니다
먼저 board 테이블 컬럼들로 BoardDto를 만들고 getter&setter를 만들어 줍니다

public class BoardDto {
    private int boardSeq;
    private int boardTypeSeq;
    private String title;
    private String content;
    private int hit;
    private String delYn;
    private String regDtm;
    private int regMemberSeq;
    private String updateDtm;
    private int updateMemberSeq;
    private String boardTypeNm;

    public int getBoardSeq() {
        return boardSeq;
    }
    public void setBoardSeq(int boardSeq) {
        this.boardSeq = boardSeq;
    }
    public int getBoardTypeSeq() {
        return boardTypeSeq;
    }
    public void setBoardTypeSeq(int boardTypeSeq) {
        this.boardTypeSeq = boardTypeSeq;
    }
    public String getTitle() {
        return title;
    }
    public void setTitle(String title) {
        this.title = title;
    }
    public String getContent() {
        return content;
    }
    public void setContent(String content) {
        this.content = content;
    }
    public int getHit() {
        return hit;
    }
    public void setHit(int hit) {
        this.hit = hit;
    }
    public String getDelYn() {
        return delYn;
    }
    public void setDelYn(String delYn) {
        this.delYn = delYn;
    }
    public String getRegDtm() {
        return regDtm;
    }
    public void setRegDtm(String regDtm) {
        this.regDtm = regDtm;
    }
    public int getRegMemberSeq() {
        return regMemberSeq;
    }
    public void setRegMemberSeq(int regMemberSeq) {
        this.regMemberSeq = regMemberSeq;
    }
    public String getUpdateDtm() {
        return updateDtm;
    }
    public void setUpdateDtm(String updateDtm) {
        this.updateDtm = updateDtm;
    }
    public int getUpdateMemberSeq() {
        return updateMemberSeq;
    }
    public void setUpdateMemberSeq(int updateMemberSeq) {
        this.updateMemberSeq = updateMemberSeq;
    }
    public String getBoardTypeNm() {
        return boardTypeNm;
    }
    public void setBoardTypeNm(String boardTypeNm) {
        this.boardTypeNm = boardTypeNm;
    }
}

join할 boardTypeNm도 작성해줍니다

BoardDao 생성

public class BoardDao extends JdbcTemplate{

}
public class BoardDao extends JdbcTemplate{

    public List<BoardDto> getList(HashMap<String, String> params){
        String sql = "SELECT b.board_seq , b.board_type_seq , b.title , b.content , b.hit , b.del_yn ,b.reg_dtm , "
                + "b.reg_member_seq , m.member_id, b.update_dtm , b.update_member_seq , bt.board_type_nm   "
                + "FROM board b  "
                + "JOIN board_type bt ON bt.board_type_seq  = b.board_type_seq  "
                + "JOIN member m ON m.member_seq  = b.reg_member_seq  "
                + "WHERE 1 = 1 "
                + "LIMIT 0, 10";
        Object[] args = {Integer.parseInt(params.get("start")) , Integer.parseInt(params.get("size"))};

        return query(sql, new BoardRowMapper(), args);
    }

    class BoardRowMapper implements RowMapper<BoardDto>{

        @Override
        public BoardDto mapRow(ResultSet rs, int rowNum) throws SQLException {
            BoardDto boardDto = null;
            while(rs.next()) {
                boardDto = new BoardDto();
                boardDto.setBoardSeq(rs.getInt("board_seq"));
                boardDto.setBoardTypeSeq(rs.getInt("board_type_seq"));
                boardDto.setTitle(rs.getString("title"));
                boardDto.setContent(rs.getString("content"));
                boardDto.setDelYn(rs.getString("del_yn"));
                boardDto.setHit(rs.getInt("hit"));
                boardDto.setRegDtm(rs.getString("reg_dtm"));
                boardDto.setRegMemberSeq(rs.getInt("reg_member_seq"));
                boardDto.setUpdateDtm(rs.getString("update_dtm"));
                boardDto.setUpdateMemberSeq(rs.getInt("update_member_seq"));
                boardDto.setBoardTypeNm(rs.getString("board_type_nm"));

            }
            return boardDto;
        }

    }
}

BoarRowMapper생성 이번에는 따로 java파일로 만들지 않고 Dao안에 클래스로 만들겠습니다 그리고 다른 테이블과 join하여 쿼리문을 작성합니다

BoardService 생성

com.pf.www.forum.notice.service.BoardService를 생성하고 dao에서 만든걸 연결해 줍니다

public List<BoardDto> getList(){
    return boardDao.getList();
}

NoticeController

service로 넘어온걸 이제 controller에 연결

private BoardService  boardService;

@RequestMapping("/forum//notice/listPage.do")
public ModelAndView listPage(@RequestParam HashMap<String, String> params) {
    ModelAndView mv = new ModelAndView();
    mv.addObject("key", Calendar.getInstance().getTimeInMillis());
    mv.setViewName("forum/notice/list");
    mv.addObject("list", boardService.getList());

    return mv;
}

BoardService

그리고 이번에는 수동이 아닌 자동 빈 등록을 위해 @Service 어노테이션을 붙여줍니다

pf-servlet

@Service을 찾아줘야하기에 위치를 설정합니다
원래는 pf-servletcomponent-scancontroller만 해줍니다
이유는 servlet파일은 철저하게 view에 관련된거이고 그와 제일 관계있는건 controller이기에 controller component-scan해줍니다

나머지 비지니스 파일은 벌도의 context를 만들어 관리를 하는게 좋습니다

그러면 pf-servlet에 있는 component-scan을 복사해서 context-bean.xml에 붙여넣습니다

context-bean.xml

<!-- Annotation 기반의 Component Scan 필터(service package 만 검색) -->
<context:component-scan base-package="com.pf.www">
    <context:include-filter type="annotation" expression="org.springframework.stereotype.Service" />
    <context:include-filter type="annotation" expression="org.springframework.stereotype.Component" />
    <context:include-filter type="regex" expression="\.*\.dao\.*" />
</context:component-scan>

이렇게해서 pf-servlet에는 controller만 스캔하고 나머지는 context-bean에서 스캔하도록 합니다
(pf-servlet은 servlet에 관계된 파일만 관리)

include-filter

  • regex : 정규식
  • annotation : 표현식

두가지 중 아무거나 쓸 수 있지만 대부분 type을 annotation으로 두는 이유는 component-scan에 있는 base-package때문입니다 (base-package아래로는 다 긁어 스캔함으로 하위식을 줄 필요 없어 annotation사용)

BoardDao

BoardDao에도 어노테이션을 달아 자동빈등록을 하겠습니다 BoardDao에는 @Repository를 넣어주시면 됩니다

context-bean.xml

<context:include-filter type="annotation" expression="org.springframework.stereotype.Repository" />

component-scan에 Repository를 추가해줍니다

BoardService

@Autowired
private BoardDao boardDao;

@Autowired를 붙여줍니다

NoticeController

@Autowired
private BoardService  boardService;

@Autowired를 붙여줍니다

BoardService

@Autowired
public void setDataSource(DataSource dataSource) {
    super.setDataSource(dataSource);
}

DataSource를 의존성주입해줍니다 dataSource는 조상인 JdbcTemplate이 사용하야 하기에 super를 붙여 줍니다