100일 챌린지/빅데이터기반 인공지능 융합 서비스 개발자

Day 45 - spring ver 2.x 문법 프로젝트 완성형

ksyke 2024. 9. 27. 12:31

목차

    Java 프로젝트 만들기

    버전 업데이트

    /pom.xml

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
      <modelVersion>4.0.0</modelVersion>
      <groupId>com.gimhae</groupId>
      <artifactId>day45_1</artifactId>
      <version>0.0.1-SNAPSHOT</version> 
      <properties>
      <spring-version>3.1.4.RELEASE</spring-version>
      </properties>
      <dependencies>
      <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring-version}</version>
        </dependency>
      <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aop</artifactId>
            <version>${spring-version}</version>
        </dependency>
      <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>${spring-version}</version>
        </dependency>
      <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>${spring-version}</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/junit/junit -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <!-- https://mvnrepository.com/artifact/log4j/log4j -->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
    
      </dependencies> 
      <build>
        <finalName>day44</finalName>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                </configuration>
            </plugin>
        </plugins>
      </build>
    </project>

    Models

    EmpVo

    package com.gimhae.model;
    
    public class EmpVo {
        private int empno,pay;
        private String ename;
        private LocalDate hiredate;
        public EmpVo() {
        }
        static class Builder{
            private int empno,pay;
            private String ename;
            private LocalDate hiredate;
            public Builder empno(int empno) {
                this.empno=empno;
                return this;
            }
            public Builder pay(int pay) {
                this.pay=pay;
                return this;
            }
            public Builder ename(String ename) {
                this.ename=ename;
                return this;
            }
            public Builder hiredate(java.sql.Date temporal) {
                this.hiredate=LocalDate.from(temporal.toLocalDate());
                return this;
            }
            public EmpVo build() {
                return new EmpVo(this);
            }
        }
        public EmpVo(Builder builder) {
            this.empno=builder.empno;
            this.ename=builder.ename;
            this.pay=builder.pay;
            this.hiredate=builder.hiredate;
        }
        public static Builder Builder() {
            return new Builder();
        }
        public int getEmpno() {
            return empno;
        }
        public void setEmpno(int empno) {
            this.empno = empno;
        }
        public int getPay() {
            return pay;
        }
        public void setPay(int pay) {
            this.pay = pay;
        }
        public String getEname() {
            return ename;
        }
        public void setEname(String ename) {
            this.ename = ename;
        }
        public LocalDate getHiredate() {
            return hiredate;
        }
        public void setHiredate(LocalDate hiredate) {
            this.hiredate = hiredate;
        }
        @Override
        public String toString() {
            return "EmpVo [empno=" + empno + ", pay=" + pay + ", ename=" + ename + "]";
        }
        @Override
        public int hashCode() {
            final int prime = 31;
            int result = 1;
            result = prime * result + empno;
            result = prime * result + ((ename == null) ? 0 : ename.hashCode());
            result = prime * result + pay;
            return result;
        }
        @Override
        public boolean equals(Object obj) {
            if (this == obj)
                return true;
            if (obj == null)
                return false;
            if (getClass() != obj.getClass())
                return false;
            EmpVo other = (EmpVo) obj;
            if (empno != other.empno)
                return false;
            if (ename == null) {
                if (other.ename != null)
                    return false;
            } else if (!ename.equals(other.ename))
                return false;
            if (pay != other.pay)
                return false;
            return true;
        }
    }

    EmpDao (Interface)

    package com.gimhae.model;
    
    public interface EmpDao {
        List<EmpVo> pullList();
        EmpVo getList(int idx);
        int addList(EmpVo bean);
        int setList(EmpVo bean);
        int rmList(int idx);
        int listSize();
    }

    EmpDaoImpl

    package com.gimhae.model;
    
    public class EmpDaoImpl implements EmpDao {
        JdbcTemplate jdbcTemplate;
    
        public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
            this.jdbcTemplate = jdbcTemplate;
        }
    
        RowMapper<EmpVo> rowMapper;
    
        public EmpDaoImpl() {
            rowMapper=new RowMapper<EmpVo>() {
    
                @Override
                public EmpVo mapRow(ResultSet rs, int rowNum) throws SQLException {
                    return EmpVo.Builder()
                            .empno(rs.getInt("empno"))
                            .ename(rs.getString("ename"))
                            .pay(rs.getInt("pay"))
                            .hiredate(rs.getDate("hiredate"))
                            .build();
                }
            };
    
        }
    
        @Override
        public List<EmpVo> pullList() {
            String sql="select * from emp38 order by empno";
            return jdbcTemplate.query(sql, rowMapper);
        }
    
        @Override
        public EmpVo getList(int idx) {
            String sql="select * from emp38 where empno=?";
            return jdbcTemplate.queryForObject(sql, rowMapper,idx);
        }
    
        @Override
        public int addList(EmpVo bean) {
            String sql="insert into emp38 (ename,pay,hiredate) values (?,?,now())";
            return jdbcTemplate.update(sql,bean.getEname(),bean.getPay());
        }
    
        @Override
        public int setList(EmpVo bean) {
            String sql="update emp38 set ename=?,pay=? where empno=?";
            return jdbcTemplate.update(sql,bean.getEname(),bean.getPay(),bean.getEmpno());
        }
        @Override
        public int rmList(int idx) {
            String sql="delete from emp38 where empno=?";
            return jdbcTemplate.update(sql,idx);
        }
    
        @Override
        public int listSize() {
            String sql="select count(*) as cnt from emp38";
            return jdbcTemplate.queryForInt(sql);
        }
    
    }

    /main/resources

    applicationContext.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"
        xmlns:p="http://www.springframework.org/schema/p"
        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    
        <bean id="dataSource"
            class="org.springframework.jdbc.datasource.DriverManagerDataSource"
            p:driverClassName="com.mysql.cj.jdbc.Driver"
            p:url="jdbc:mysql://localhost:3306/xe"
            p:username="scott" p:password="tiger"
        />
        <bean id="jdbcTemplate"
            class="org.springframework.jdbc.core.JdbcTemplate"
            p:dataSource-ref="dataSource"
        />
        <bean id="empDao"
            class="com.gimhae.model.EmpDaoImpl"
            p:jdbcTemplate-ref="jdbcTemplate"
        />
    
    </beans>

    log4j.properties

    log4j.rootLogger=WARN, A1
    log4j.appender.A1=org.apache.log4j.ConsoleAppender
    log4j.appender.A1.layout=org.apache.log4j.PatternLayout
    
    # Print the date in ISO 8601 format
    log4j.appender.A1.layout.ConversionPattern=%c - %m%n
    
    # Print only messages of level WARN or above in the package com.foo.
    log4j.logger.com.gimhae.model=debug

    Test cases

    EmpDaoTest.java

    package com.gimhae.model;
    
    public class EmpDaoTest {
        static ApplicationContext ac;
        EmpDao empDao;
        EmpVo target;
    
        @BeforeClass
        public static void setUpBeforeClass() throws Exception {
            ac=new ClassPathXmlApplicationContext("/applicationContext.xml");
        }
    
        @Before
        public void setUp() throws Exception {
            empDao=ac.getBean(EmpDao.class);
            target=EmpVo.Builder().empno(4).pay(4444).ename("tester004").build();
        }
    
        @Test
        public void testPullList() {
            List<EmpVo> list=empDao.pullList();
            assertNotNull(list);
            assertTrue(list.size()>0);
        }
        @Test
        public void testGetlList() {
            assertEquals(target, empDao.getList(target.getEmpno()));
        }
        @Test
        public void testAddlList() {
            target.setEname("new1");
            target.setPay(1111);
            assertSame(1,empDao.addList(target));
        }
        @Test
        public void testListSize() {
            assertNotSame(0,empDao.listSize());
        }
        @Test
        public void testSetList() {
            target.setEname("tester4");
            assertSame(1,empDao.setList(target));
        }
        @Test
        public void testRmList() {
            assertSame(1,empDao.rmList(34));
        }
    
    }

    Log messgage 출력하기

    ArroundLog.java

    package com.gimhae.aop;
    
    public class AroundLog implements MethodInterceptor {
        Logger log;
    
        @Override
        public Object invoke(MethodInvocation ivc) throws Throwable {
            log=Logger.getLogger(ivc.getThis().getClass());
            Object[] args=ivc.getArguments();
            log.debug("params:"+Arrays.toString(args));
            Object obj=ivc.proceed();
            log.debug("return:"+obj);
            return obj;
        }
    }

    applicationContext.xml

        ...
        <bean id="advice"
            class="com.gimhae.aop.AroundLog"
        />
    
        <bean id="pointcut"
            class="org.springframework.aop.support.NameMatchMethodPointcut">
            <property name="mappedNames">
                <list>
                    <value>pullList</value>
                </list>
            </property>
        </bean>
    
        <bean id="pointcutAdvisor"
            class="org.springframework.aop.support.DefaultPointcutAdvisor"
            p:pointcut-ref="pointcut"
            p:advice-ref="advice"
        />
    
        <bean 
            class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"
            p:beanNames="empDao"
            p:interceptorNames="pointcutAdvisor"
        />
        ...

    Transaction

    2개 이상의 query 문장이 실행될 떄, 동시에 실행되거나, 한 문장이 실패할떄 발생하는 문제를 없애기 위해 transaction이 사용된다.

    EmpDaoImpl

    public class EmpDaoImpl2 implements EmpDao {
        JdbcTemplate jdbcTemplate;
        PlatformTransactionManager transactionManager;
        ...
    }
        ...
        @Override
        public List<EmpVo> pullList() {
            String sql="select * from emp38 order by empno";
            PreparedStatementCreator psc=null;
            psc=new PreparedStatementCreator() {
    
                @Override
                public PreparedStatement createPreparedStatement(Connection con) throws SQLException {
                    PreparedStatement pstmt=con.prepareStatement(sql);
                    return pstmt;
                }
            };
            return jdbcTemplate.query(psc, rowMapper);
        }
    
        @Override
        public EmpVo getList(int idx) {
            String sql="select * from emp38 where empno=?";
            return jdbcTemplate.queryForObject(sql, rowMapper,idx);
        }
    
        @Override
        public int addList(EmpVo bean) {
            String sql="insert into emp38 (ename,pay,hiredate) values (?,?,now())";
            String sql2="insert into emp38 (empno,ename,pay,hiredate) values (4,?,?,now())";
    
            TransactionDefinition definition=new DefaultTransactionDefinition();
            TransactionStatus status=transactionManager.getTransaction(definition);
            try {
            PreparedStatementCreator psc=null;
            psc=new PreparedStatementCreator() {
    
                @Override
                public PreparedStatement createPreparedStatement(Connection con) throws SQLException {
                    System.out.println(con.hashCode());
                    PreparedStatement pstmt=con.prepareStatement(sql);
                    pstmt.setString(1, bean.getEname());
                    pstmt.setInt(2, bean.getPay());
                    return pstmt;
                }
            };
            jdbcTemplate.update(psc);
            psc=new PreparedStatementCreator() {
    
                @Override
                public PreparedStatement createPreparedStatement(Connection con) throws SQLException {
                    System.out.println(con.hashCode());
                    PreparedStatement pstmt=con.prepareStatement(sql2);
                    pstmt.setString(1, bean.getEname());
                    pstmt.setInt(2, bean.getPay());
                    return pstmt;
                }
            };
            int result=jdbcTemplate.update(psc);
            transactionManager.commit(status);
            return result;
            }catch(Exception e) {
                transactionManager.rollback(status);
                return 0;
            }
        }
        ...
    }

    혹은

    simpler version:
    public class EmpDaoImpl implements EmpDao {
        JdbcTemplate jdbcTemplate;
        PlatformTransactionManager transactionManager;
        TransactionDefinition definition;
        ...
    }
        ...
        @Override
        public int addList(EmpVo bean) {
            String sql="insert into emp38 (ename,pay,hiredate) values (?,?,now())";
            int result=0;
    
            TransactionStatus status=transactionManager.getTransaction(definition);
            try {
                result=jdbcTemplate.update(sql,bean.getEname(),bean.getPay());
                transactionManager.commit(status);
            }catch (Exception e) {
                transactionManager.rollback(status);
            }
            return result;
        }
        ...

    applicationContext.xml

        ...
        <bean id="transactionManager"
            class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
            p:dataSource-ref="dataSource"
        />
        <bean id="empDao"
            class="com.gimhae.model.EmpDaoImpl2"
            p:jdbcTemplate-ref="jdbcTemplate"
            p:transactionManager-ref="transactionManager"
        />
        ...

    RollBack - 실패시 packaging이 진행되도록 Rollback

    EmpDaoTest

        ...
        @Before
        public void setUp() throws Exception {
            empDao=ac.getBean(EmpDao.class);
            //EmpVo [empno=4, pay=4444, ename=tester4];
            target=EmpVo.Builder()
                        .empno(4)
                        .pay(4444)
                        .ename("tester4")
                        .build();
    
            PlatformTransactionManager manager=ac.getBean(PlatformTransactionManager.class);
            manager.getTransaction(ac.getBean(TransactionDefinition.class)).setRollbackOnly();
        }
        ...

    Maven web 프로젝트 만들기

    pom.xml 라이브러리 업데이트 -[web, webmvc, servlet, jsp]

        ...
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>${spring-version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${spring-version}</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>javax.servlet.jsp</groupId>
            <artifactId>javax.servlet.jsp-api</artifactId>
            <version>2.3.3</version>
            <scope>provided</scope>
        </dependency>
        ...

    maven clean

    -[Run As] > [Maven Build]

    convert to maven project

    - [configure] > [convert to Maven Project]

    make web.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app version="3.1" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee                       http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd">
    
    </web-app>

    Spring 프로젝트 만들기

    Servlet Mapping

    web.xml

        ...
        <servlet>
            <servlet-name>day45</servlet-name>
            <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
            <init-param>
                <param-name>contextConfigLocation</param-name>
                <param-value>/WEB-INF/servlet/day45-servlet.xml</param-value>
            </init-param>
        </servlet>
        <servlet-mapping>
            <servlet-name>day45</servlet-name>
            <url-pattern>*.do</url-pattern>    
        </servlet-mapping>
        ...

    Controller

    day45-servlet.xml

    --

    applicationContext.xml

        ...
        <bean 
            class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"
        />

    ListController

    package com.gimhae.controller;
    
    public class ListController implements Controller {
        EmpDao empDao;
    
        @Autowired
        public void setEmpDao(EmpDao empDao) {
            this.empDao = empDao;
        }
    
        @Override
        public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) throws Exception {
            return new ModelAndView("emp/list","list",empDao.pullList());
        }
    }

    InsertController

    --

    DeleteController

    --

    Pages

    /index.jsp

    ...
    <script type="text/javascript">
    location.href="index.do"
    </script>
    ...

    views/template/head.jspf

    ...
    <%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
    <c:set var="root" value="${pageContext.request.contextPath}"></c:set>
    <link rel="stylesheet" type="text/css" href="${root }/css/bootstrap.min.css">
    <script type="text/javascript" src="${root }/js/jquery-1.12.4.min.js"></script>
    <script type="text/javascript" src="${root }/js/bootstrap.min.js"></script>
    <style type="text/css">
    body {
      padding-top: 50px;
    }
    .starter-template {
      padding: 40px 15px;
      text-align: center;
    }
    </style>

    views/template/menu.jspf

    ...
        <!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
        <script src="https://code.jquery.com/jquery-1.12.4.min.js" integrity="sha384-nvAa0+6Qg9clwYCGGPpDQLVpLNn0fRaROjHqs13t4Ggj3Ez50XnGQqc/r8MhnRDZ" crossorigin="anonymous"></script>
        <!-- Include all compiled plugins (below), or include individual files as needed -->
        <script src="https://cdn.jsdelivr.net/npm/bootstrap@3.4.1/dist/js/bootstrap.min.js" integrity="sha384-aJ21OjlMXNL5UyIl/XNwTMqvzeRMZH2w8c5cRVpzpU8Y5bApTppSuUkhZXN0VxHd" crossorigin="anonymous"></script>
    
     <nav class="navbar navbar-inverse navbar-fixed-top">
          <div class="container">
            <div class="navbar-header">
              <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
                <span class="sr-only">Toggle navigation</span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
              </button>
              <a class="navbar-brand" href="#">Project name</a>
            </div>
            <div id="navbar" class="collapse navbar-collapse">
              <ul class="nav navbar-nav">
                <li><a href="${root }/">home</a></li>
                <li><a href="${root }/intro.do">intro</a></li>
                <li><a href="${root }/emp/list.do">emp</a></li>
                <li><a href="${root }/login/login.do">login</a></li>
              </ul>
            </div><!--/.nav-collapse -->
          </div>
        </nav>
    <div class="container">
          <div class="starter-template">
            <div class="row">
                <div class="col-md-12">

    views/template/footer.jspf

    ...
    </div>
    </div>
            <div class="col-md-12">
                <address>
                    <p>김해캠퍼스 (50834) 경남 김해시 인제로 197</p>
                    <p>Copyright &copy;2024 INJE University. All rights reserved.</p>
                </address>
            </div>
        </div>
    </div></html>

    views/main.jsp

    ...
    
    <%@include file="template/head.jspf" %>
    ...
    <%@include file="template/menu.jspf" %>
    
                <div class="jumbotron">
                    <h2>환영합니다.</h2>
                </div>
    
    <%@include file="template/footer.jspf" %>
    ...

    views/intro.jsp

    ...
    <%@include file="template/head.jspf" %>
    ...
    <%@include file="template/menu.jspf" %>
    
                <img src="https://www.inje.ac.kr/kor/assets/images/sub/gimhae-campus-1.jpg">
    
    <%@include file="template/footer.jspf" %>
    ...

    views/emp/list.jsp

    ...
    <%@include file="../template/head.jspf" %>
    ...
    <%@include file="../template/menu.jspf" %>
    
        <h2 class="page-header">목록</h2>
        <table class="table">
             <thead>
                <tr>
                    <td>사번</td>
                    <td>이름</td>
                    <td>금액</td>
                    <td>날짜</td>
                </tr>
            </thead>
            <tbody>
                <c:forEach items="${list }" var="bean">
                <c:url value="detail.do" var="detail">
                    <c:param name="idx" value="${bean.empno }"/>
                </c:url>
                    <tr>
                        <td><a href="${detail }">${bean.empno }</a></td>
                        <td><a href="${detail }">${bean.ename }</a></td>
                        <td><a href="${detail }">${bean.pay }</a></td>
                        <td><a href="${detail }">${bean.hiredate }</a></td>
                    </tr>
                </c:forEach>
            </tbody>
        </table>
    
    <%@include file="../template/footer.jspf" %>
    ...

    views/emp/add.jsp

    --

    DB 정보 property로 따로 보관하기

    applicationContext.xml

    	...
    	<bean class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer"
    		p:location="classpath:/db.properties"
    	/>
    
    	<bean id="dataSource"
    		class="org.springframework.jdbc.datasource.DriverManagerDataSource"
    		p:driverClassName="com.mysql.cj.jdbc.Driver"
    		p:url="${db.mysql.url}"
    		p:username="${db.mysql.user}" p:password="${db.mysql.password}"
    	/>
        ...

    db.properties

    db.mysql.url=jdbc:mysql://localhost:3306/xe
    db.mysql.user=scott
    db.mysql.password=tiger