본문 바로가기
kosta/Spring

Spring 기초3(실습)

by 엑츄얼리 2022. 5. 18.

게시판에 게시글 CRUD + tiles

Setting

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<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.kosta.spring</groupId>
    <artifactId>Kosta_Spring_Maven</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
    </properties>
    <dependencies>
        
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>4.3.20.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>4.3.20.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>4.3.20.RELEASE</version>
        </dependency>
        
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-validator</artifactId>
            <version>4.3.2.Final</version>
        </dependency>

        <!--mybatis spring 연동-->
        
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>4.3.20.RELEASE</version>
        </dependency>

        
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.2.6</version>
        </dependency>

        
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>1.2.0</version>
        </dependency>
        
        <dependency>
            <groupId>org.apache.tiles</groupId>
            <artifactId>tiles-jsp</artifactId>
            <version>3.0.7</version>
        </dependency>

        
        <dependency>
            <groupId>org.apache.tiles</groupId>
            <artifactId>tiles-core</artifactId>
            <version>3.0.7</version>
        </dependency>

        
        <dependency>
            <groupId>org.apache.tiles</groupId>
            <artifactId>tiles-servlet</artifactId>
            <version>3.0.7</version>
        </dependency>
    </dependencies>
</project>

* spring-aspects는 aop관련해서 사용되는 dependency로 알고 있으며 다른 부분에서 쓰여서 남겨놓았다.

 

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app 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_4_0.xsd"
         version="4.0">

<!--*************************************************************************************-->
    <servlet>
        <servlet-name>dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <load-on-startup>3</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>dispatcher</servlet-name>
        <url-pattern>/</url-pattern>
    </servlet-mapping>
<!--*************************************************************************************-->
    <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>
    </filter>

    <filter-mapping>
        <filter-name>encodingFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

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

 

dispatcher-servlet.xml

* web.xml의 <servlet-name>dispatcher</servlet-name>에 관한 설정 파일이다. (자동 매칭)

<?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:context="http://www.springframework.org/schema/context"
       xmlns:jee="http://www.springframework.org/schema/jee" xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <bean id="viewResolver"
          class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/view/Day0516"/>
        <property name="suffix" value=".jsp"/>
        <property name="contentType" value="text/html; charset=UTF-8"/>
        <property name="order" value="2"/>
    </bean>

    <!--Tiles Setting-->
    <bean id="viewResolver2"
          class="org.springframework.web.servlet.view.UrlBasedViewResolver">
        <property name="viewClass"
                  value="org.springframework.web.servlet.view.tiles3.TilesView"/>
        <property name="order" value="1"/>
    </bean>

    <bean id="tilesConfigurer"
          class="org.springframework.web.servlet.view.tiles3.TilesConfigurer">
        <property name="definitions">
            <list>
                <value>/WEB-INF/tilesDef.xml</value>
            </list>
        </property>
    </bean>
    <!--Mybatis Setting-->
    <context:annotation-config/>
    <mvc:annotation-driven/>
    <mvc:default-servlet-handler/>
    <context:component-scan base-package="Day0516.*"/>

    <jee:jndi-lookup id='myDataSource' jndi-name='jdbc/oracle' expected-type="javax.sql.DataSource"/>

    <!--아래가 eclipse setting인데 intellij 에서는 동작하지 않는다. myDataSource type이 javax.sql.DataSource가 아니라고 한다.
        구체적인 데이터 타입이냐 아니냐의 차이였던 것 같은데 아래 코드를 수정하는 방법은 아무리 찾아도 찾지 못했다.
        따라서 위와 같이 수정하였고 동작에 성공했다.-->
    <!--    <bean id="myDataSource"-->
    <!--          class="org.springframework.jndi.JndiObjectFactoryBean">-->
    <!--        <property name="jndiName" value="jdbc/oracle"/>-->
    <!--        <property name="resourceRef" value="true"/>-->
    <!--    </bean>-->


    <bean id="sqlSessionFactory"
          class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="myDataSource"/>
        <property name="configLocation" value="/WEB-INF/mybatis-config.xml"/>
    </bean>

    <bean id="sqlSessionTemplate"
          class="org.mybatis.spring.SqlSessionTemplate">
        <constructor-arg name="sqlSessionFactory" ref="sqlSessionFactory"/>
    </bean>
</beans>

간략하게 설명하면,

 - bean viewResolver는 controller의 return 값의 앞뒤로 prefix와 suffix를 결합하여 view파일의 경로를 설정

    <property name="order" value="2"/>

 

 - bean viewResolver2도 위와 같은 역할을 하며 <property name="order" value="1"/>이므로

    viewResolver보다 우선 순위가 높아 controller에서 return값이 반환되면 먼저 처리하게 된다.

    해당 bean이 viewResolver bean인지는 id를 통해서 판별하는게 아닌 value를 통해서 판별하는 것 같다. 

     (id 값을 바꿔도 viewResolver가 정상적으로 bean을 처리하며, (ex. viewResolver2를 a로)

      org.springframework.web.servlet.view의 view 부분이 관리하는 것 같다.)

 

 - bean tilesConfigurer는 tile Config File의 위치를 지정

   (마지막 Class부분을 제외하고,

class="org.springframework.web.servlet.view.tiles3.

   이 부분이 viewResolver2와 공통인 것으로 보아 앞서 언급했던 view class에서

    TilesView(viewResolver2)와 TilesConfigurer(tilesConfigurer)를 일괄적으로 관리하는 것 같다.)

 

 - 아래 부분은 주석으로 설명해놨으므로 생략 (진짜 오래 걸렸다 ㅠㅠ...)

<jee:jndi-lookup id='myDataSource' jndi-name='jdbc/oracle' expected-type="javax.sql.DataSource"/>

 

 - bean sqlSessionFactory와 sqlSessionTemplate

   sqlSessionFactory는 연결할 데이터 베이스(context.xml)에 대한 정보와

                                        mybatis(mybatis-config.xml) 설정 정보를 담고 있는 부분

    (Factory라는 부분을 아직 잘 모르겠는데, 아마 connection pool과 관련이 있지 않을까 싶다)

   sqlSessionTemplate는 쿼리문을 실행할 수 있는 부분

 

 

View

insert_form.jsp (이 부분부터 실행하여 동작)

<%@ page language="java" contentType="text/html; charset=utf-8"
         pageEncoding="utf-8"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
    <title>Insert title here</title>
    <style type="text/css">
        .error{
            color: #ff0000;
        }
    </style>
</head>
Day0516
<body>
<h3>글쓰기</h3>
<hr>
<%--@elvariable id="boardCommand16" type="Day0516"--%>
<form:form action="board_insert" method="post"
           modelAttribute="boardCommand16">
    작성자 : <form:input type="text" path="writer"/>
    <form:errors path="writer" cssClass="error"/> <br>
    제목 : <form:input type="text" path="title"/>
    <form:errors path="title" cssClass="error"/><br>
    내용 <br>
    <form:textarea rows="6" cols="70" path="contents"></form:textarea>
    <br>
    <input type="submit" value="등록">
</form:form>
</body>
</html>

 

list.jsp

<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>

<html>
<head>
    <title>Title</title>
</head>
<body>
<a href="/board_insert">글쓰기</a>
<table border="1">
    <tr>
        <td>글 번호</td>
        <td>제목</td>
        <td>작성자</td>
        <td>작성 일자</td>
        <td>조회수</td>
    </tr>
    <c:forEach var="board" items="${list}">
        <tr>
            <td>${board.seq}</td>

            <td><a href="board_detail/${board.seq}">${board.title}</a></td>
            <td>${board.writer}</td>
                <%--board.regdate는 String 타입이다. 따라서 Date 타입으로 변경해야함--%>
            <td>
                <fmt:parseDate var="dateTime" value="${board.regdate}" pattern="yyyy-MM-dd HH:mm:ss"/>
                <fmt:formatDate value="${dateTime}" pattern="yyyy-MM-dd"/>
            </td>
            <td>${board.hitcount}</td>
        </tr>
    </c:forEach>
</table>
<br><br>
</body>
</html>

 

detail.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
<table border="1">
    <tr>
        <td>글 번호</td>
        <td>제목</td>
        <td>작성자</td>
        <td>작성 일자</td>
        <td>조회수</td>
        <td>글 내용</td>
    </tr>
    <tr>
        <td>${board.seq}</td>
        <td>${board.title}</td>
        <td>${board.writer}</td>
        <td>${board.regdate}</td>
        <td>${board.hitcount}</td>
        <td>${board.contents}</td>
    </tr>
</table>

<h4>댓글 목록</h4>
<table border="1">
    <tr>
        <td>댓글 번호</td>
        <td>댓글 제목</td>
        <td>댓글 작성자</td>
        <td>댓글 내용</td>
    </tr>
    <c:forEach var="reply" items="${listReply}">
        <tr>
            <td>${reply.r_no}</td>
            <td>${reply.r_title}</td>
            <td>${reply.r_writer}</td>
            <td>${reply.r_contents}</td>
        </tr>
    </c:forEach>
</table>

<a href="/board_update?seq=${board.seq}" >글 수정하기</a>
<a href="/board_delete?seq=${board.seq}">글 삭제하기</a>

</body>
</html>

 

updateForm.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>

<html>
<head>
    <title>Title</title>
</head>
<body>
<h3>글 수정폼</h3>
<form action="board_update" method="post">
    <input type="hidden" name="seq" value="${board.seq}"/>
    작성자 : ${board.writer}<br>
    제목 : <input type="text" name="title" value="${board.title}"><br>
    내용 : <br>
    <textarea rows="6" cols="70" name="contents">${board.contents}</textarea>
    <input type="submit" value="수정 완료">
</form>
</body>
</html>

 

 

Controller

package Day0516.controller;

import Day0516.model.Board;
import Day0516.model.BoardDao16;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;

@Controller
public class BoardController16 {
    @Autowired
    private BoardDao16 dao;

    @GetMapping("/board_insert")
    public String board_form(@ModelAttribute("boardCommand16") Board board) {
        System.out.println("GET");
        return "insert_form";
    }

    //@RequestMapping(value="/board_insert", method= RequestMethod.POST)
    @PostMapping("/board_insert")
    public String board_insert(@ModelAttribute("boardCommand16") @Valid Board board, BindingResult errors) {
        System.out.println("POST");
        if (errors.hasErrors()) {
            System.out.println("에러발생");
            return "insert_form";
        }
        dao.insert(board);

        return "redirect:board_list";
    }

    @RequestMapping("/board_list")
    public String board_list(Model model) {
        model.addAttribute("list", dao.list());
        return "list";
    }

    @RequestMapping("/board_detail/{seq}")
    public String board_detail(@PathVariable int seq, Model model) {
        model.addAttribute("board", dao.detail(seq));
        return "detail";
    }

    @GetMapping("/board_update")
    public String board_form(@RequestParam("seq") int seq, Model model) {
        model.addAttribute("board", dao.detail(seq));
        return "updateForm";
    }

    @PostMapping("/board_update")
    public String board_update(Board board) {
        dao.update(board);
        return "redirect:board_list";
    }

    @GetMapping("/board_delete")
    public String board_delete(@RequestParam(name="seq", value="seq") int seq){
        dao.delete(seq);
        return "redirect:board_list";
    }
}

@RequestParam

 - 쿼리스트링 방식 (ex. localhost:8080/board_update?seq=10)을 통해 여러개의 값을 전달할 때

 

  속성 값 : value (uri에서 바인딩할 값)

              required (true로 설정 시, 값이 전달되지 않으면 error 발생)

              defaultValue (값이 없을 때, 기본 값 설정)

              ex)

@RequestParam(value="seq", required=true, defaultValue="10")int seq

 * 호기심에 해본 코드인데 required=true이고 defaultValue="10"으로 설정했을 때 seq값을 넘기지 않으면 오류가 발생

   같이 쓸일은 없을 것 같아서 상관은 없을 듯

 

 

@PathVariable

 - URI뒤에 /{value]를 통해 하나의 값을 전달할 때 (ex. localhost:8080/board_update/10)

 

 - controller method에서 String등의 파라미터가 선언되었을 경우,

    @RequestParam(value={value}, required=false)을 가정 하므로 controller methond에서

     아래 두개의 코드는 같은 의미이다.

@RequestParam(value="seq", required=false)int seq

int seq

 

 

Dao

BoardDao16.java

package Day0516.model;

import Day0516.mapper.BoardMapper;
import org.apache.ibatis.session.RowBounds;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

@Repository
public class BoardDao16 {

    @Autowired
    private SqlSessionTemplate sqlSessionTemplate;

    public void insert(Board board) {
        sqlSessionTemplate.getMapper(BoardMapper.class).insertBoard(board);
    }

    public void update(Board board) {
        sqlSessionTemplate.getMapper(BoardMapper.class).updateBoard(board);
    }

    public Object detail(int seq) {
        return sqlSessionTemplate.getMapper(BoardMapper.class).detailBoard(seq);
    }

    public Object list() {
        return sqlSessionTemplate.getMapper(BoardMapper.class).listBoard(new RowBounds(0, 5));
    }

    public void delete(int seq) {
        sqlSessionTemplate.getMapper(BoardMapper.class).deleteBoard(seq);
    }
}

 

 * Setting : context.xml, mybatis-config.xml,

   Model : Board.java

   mapper : BoardMapper.java, Board.xml

   정도는 복습하면서 만들자. 이정도는 해야지!!!

   

 

tiles

사실 xml을 통한 setting이 다인 것 같다.

 

tilesDef.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE  tiles-definitions PUBLIC
        "-//Aapche Software Foundation//DTD Tiles Configuration 3.0//EN"
        "http://tiles.apache.org/dtds/tiles-config_3_0.dtd"
        >
<tiles-definitions>
    <definition name="base_layout" template="/WEB-INF/view/Day0516/module/template.jsp">
        <put-attribute name="header" value="/WEB-INF/view/Day0516/module/header.jsp"/>
        <put-attribute name="logo" value="/WEB-INF/view/Day0516/module/logo.jsp"/>
        <put-attribute name="footer" value="/WEB-INF/view/Day0516/module/footer.jsp"/>
    </definition>

    <definition name="*" extends="base_layout">
        <put-attribute name="body" value="/WEB-INF/view/Day0516/{1}.jsp"/>
    </definition>
</tiles-definitions>

bean tileConfigurer와 매칭되는 파일이다. (dispatcher-servlet.xml에 설정 있음)

<put-attribute name에 따라서 읽어온 view파일을 특정위치에 붙인(?)다.

<definition name="*" ~ >을 통해 모든 파일에 타일을 입히는 방식만 알아두고 넘어가면될 것 같다.

 

코드는 가볍게 스크린샷으로 대체하겠다.

template.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="tiles" uri="http://tiles.apache.org/tags-tiles" %>    
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
   <!-- 헤더영역 -->
   <tiles:insertAttribute name="header"/>
   <hr>

<%--로고 영역--%>
   <tiles:insertAttribute name="logo"/>
   <hr>

   <!-- 바디영역 -->
   <tiles:insertAttribute name="body"/>
   <hr>
   
   <!-- 푸터영역 -->
   <tiles:insertAttribute name="footer"/>
</body>
</html>

 

footer.jsp
header.jsp
logo.jsp

 

<localhost:8080/board_insert> 결과

 

 

간단한 AOP와 Transaction

AOP

Settings

 * .xml파일은 위의 것을 토대로 진행하였으므로 추가된 부분만 작성

 

pom.xml

    <!--AOP Setting-->
    <aop:aspectj-autoproxy/>
    <bean id="sessionAspect" class="Day0517.aspect.SessionAspect"/>

 

 

View

* 주요 부분만 스크린샷으로 대체

session_req.jsp
session_add.jsp
session_success.jsp
session_fail.jsp

 

 

Controller

SessionController.java

package Day0517.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpServletRequest;

@Controller
public class SessionController {
    @RequestMapping("/session_req")
    public String session_req() {
        return "session/session_req";
    }

    @RequestMapping("/session_do")
    public String session_do(HttpServletRequest request) {
        return "session/session_success";
    }

    @RequestMapping("session_add")
    public String session_add(){
        return "session/session_add";
    }
}

 

 

Aspects

SessionAspect.java

package Day0517.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

@Aspect
public class SessionAspect {
    @Around("execution(public * Day0517.controller.*.*do(..))")
    public String sessionCheck(ProceedingJoinPoint joinPoint)throws Throwable{
        Object[] obj = joinPoint.getArgs();
        HttpServletRequest request = (HttpServletRequest) obj[0];
        HttpSession session = request.getSession();

        String name = (String)session.getAttribute("name");
        String view = "session/session_fail";

        try{
            if (name == null){
                throw new Exception("no session");
            }
            view = (String)joinPoint.proceed();//session_do() 호출
        }catch(Exception e){
            return view;
        }
        return view;
    }
}

(중요) pom.xml에서 추가했던 bean에 의해 Controller가 처리 후 return 값을 dispatcher에 반환하기 전에 @Aspect가 @Around의 execution 조건을 통해 추가 로직을 실행한다. 

 해당 수업에서는 Server to Client 부분만 구현되었지만, Client to Server부분에서도 로직을 실행할 수 있으며,

  Proxy와 같은 개념이다.

 

 

Transaction

Settings

pom.xml

<tx:annotation-driven transaction-manager="transactionManager"/>
<bean id="transactionManager"
      class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="DataSource" ref="myDataSource"/>
</bean>

 

Controller

package Day0517.controller;

import Day0517.model.Order;
import Day0517.service.OrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class orderController {
    @Autowired
    private OrderService service;

    @RequestMapping("/orderForm")
    public String orderForm() {
        return "transaction/orderForm";
    }

    @PostMapping("orderAction")
    public String orderAction(Order order) {
        String view = "transaction/orderOk";

        try {
            service.orderAction(order);
        } catch (Exception e) {
            view = "transaction/orderForm";
        }

        return view;
    }
}

 

Service

package Day0517.service;

import Day0517.model.ItemDao;
import Day0517.model.Order;
import Day0517.model.OrderDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

@Service
public class OrderService {
    @Autowired
    private OrderDao orderDao;

    @Autowired
    private ItemDao itemDao;

    //주문서비스 구현
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = {Exception.class})
    public void orderAction(Order order) throws Exception {
        //주문 등록
        orderDao.addOrder(order);

        //재고 조정
        //1. 재고 부족 => 예외 발생
        if(itemDao.findItem(order.getNo()).getAmount() < order.getAmount()){
            throw new Exception("재고 부족");
        }

        //2. 재고 있음
        itemDao.updateItem(order);

    }
}

 

 

View

orderForm.jsp

<%@ page language="java" contentType="text/html; charset=EUC-KR"
    pageEncoding="EUC-KR"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=EUC-KR">
<title>Insert title here</title>
</head>
<body>
   <h3>주문내역</h3>
   <form action="orderAction" method="post">
      <input type="hidden" name="no" value="100">
      <input type="hidden" name="name" value="pc">
      <input type="hidden" name="price" value="10000">
      컴퓨터 : 
      <select name="amount">
         <option value="1">1</option>
         <option value="2">2</option>
         <option value="1000">1000</option>
         <option value="5000">5000</option>
      </select>
      <br><br>
      <input type="submit" value="주문">
   </form>
</body>
</html>

 

orderOk.jsp

<%@ page language="java" contentType="text/html; charset=EUC-KR"
    pageEncoding="EUC-KR"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=EUC-KR">
<title>Insert title here</title>
</head>
<body>
성공
</body>
</html>

 

* Dao랑 Model은 생략했다. (이 부분에서는 중요하지 않은 것 같아서)

 

Service를 잘 이해하는게 중요하다고 느꼈는데, 

[주문 등록] 부분에 orderDao.addOrder(order)을 통해 order Table에 order를 추가해준다. (중요! commit은 하지 않음)

 

[1.재고부족]상황 시 Exception을 발생 시켜, [주문 등록]에서 수정한 DB를 rollback

 

[2.재고 있음]상황 시 updateItem(order)를 통해  item Table에서 재고를 수정,

                           메서드가 정상적으로 종료되었으므로, commit!

 

commit과 rollback은 dispatcher-servlet.xml의 Transaction Setting 부분에

class="org.springframework.jdbc.datasource.DataSourceTransactionManager"

DataSourceTransactionManager 클래스 내부에서 찾을 수 있었다.

과정을 보고 싶어서 디버그도 돌려보고 했는데, 너무 깊은 것 같기도 하고 코드도 막연해서 이해는 잘 안되었지만, 

 이 부분을 통해 @Transactional 이 관리됨을 알 수 있었다.

 (DB의 rollback과 commit, 즉 transaction과정 전반에 대한 처리)

 

 


오류 및 공부하다 할게된 것

1. jsp에 tiles 설정을 하는 과정에서 tilesDef.xml에

<!DOCTYPE  tiles-definitions PUBLIC
        "-//Aapche Software Foundation//DTD Tiles Configuration 3.0//EN"
        "http://tiles.apache.org/dtds/tiles-config_3_0.dtd"
        >

이 부분이 War Artifacts의 Lib 내부의 tiles version과 맞지 않았었다.

이 부분이 틀리니 xml 설정 과정에서 오류가 발생하여 WEB-INF폴더 내부의 jsp파일들을 아래와 같이 제대로 읽지 못했다. 아마 WEB-INF에 RequestForward 방식으로 접근이 안되어서 JSP내부 html을 읽지 못한다. 따라서 경로만 출력된다.

저 부분을 위와 같이 올바르게 수정하면 제대로 출력이된다.

 

* xml설정에서 오류가 정말 많이 발생한다.

   xml 부분, 즉 세팅 부분이 정말 이해하기도 어렵고 신경도 많이 쓰이는 것 같다. 

   가끔 귀찮아서 그냥 그런가보다 하고 넘어가고 싶더라도 꼭 이 부분만은 제대로 이해하고 넘어가면 좋을 것 같다.

 

 

2. <url-pattern>에서 /와 /*을 차이

 / : 설정에서 url-pattern이 적용되지 않은 모든 URL

 /* : 모든 url-pattern

 위와 같이 간략하게는 이해가 안될 수 있어 예를 들어보겠다.

  web.xml에 아래와 같이 servlet-mapping 설정이 되어 있다면

<servlet>
    <servlet-name>dispatcher</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <load-on-startup>3</load-on-startup>
</servlet>
<servlet-mapping>
    <servlet-name>dispatcher</servlet-name>
    <url-pattern>/</url-pattern>

</servlet-mapping>


<servlet>
    <servlet-name>springapp</servlet-name>
    <servlet-class>
        org.springframework.web.servlet.DispatcherServlet
    </servlet-class>
    <load-on-startup>2</load-on-startup>
</servlet>

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

/의 경우 <url-pattern>이 *.do가 아닌 모든 url에 적용된다.

/*의 경우 <url-pattern>이 *.do인 url을 포함한 모든 url에 적용된다.

* <load-on-startup>같은 경우 톰켓 실행 시 servlet의 초기화 순서를 의미한다.

   (아직 이해가 잘 되지 않아 나중에 제대로 이해하고 수정)

 

 

3. mybatis를 통해 mvc와 db를 연결 시 Mapper에서 ResultType을 통해 받아오는 객체에

   get Method나 생성자가 없더라도 데이터가 받아와서 저장이 된다. 어떻게 되는지는 모르겠다...ㅎㅎ 찾아도 안나온다.

 

 

* 궁금한게 너무 많아서 이것 저것 찾다보니까 결국에는 스프링 내부 구동 순서나 로직들을 이해를 해야

   호기심이 풀린다는 것을 알았다. 만약 다음에 복습할 때 이 글을 보는데 아직도 모르면 진짜 반성 많이해라 너는...

'kosta > Spring' 카테고리의 다른 글

@ModelAttribute 추가 이해  (0) 2022.06.14
Maven 기반 Spring 프로젝트 생성!  (0) 2022.05.18
Spring 기초2(실습)  (0) 2022.05.16
Spring 기초(실습)  (0) 2022.05.12

댓글