게시판에 게시글 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>
<localhost:8080/board_insert> 결과
간단한 AOP와 Transaction
AOP
Settings
* .xml파일은 위의 것을 토대로 진행하였으므로 추가된 부분만 작성
pom.xml
<!--AOP Setting-->
<aop:aspectj-autoproxy/>
<bean id="sessionAspect" class="Day0517.aspect.SessionAspect"/>
View
* 주요 부분만 스크린샷으로 대체
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 |
댓글