@AllArgsConstructor
@NoArgsConstructor
두 줄을 클래스 위에 써주면 생성자 알아서 만들어준다.
@GetMapping 작성할 때, return에 .jsp 파일의 경로를 써주면, 그 페이지를 리턴한다.redirect:{파일명}이라고 써주면, 그쪽으로 페이지를 리다이렉팅한다.@GetMapping("/insertOk")
public String insertOk(@RequestParam String id, @RequestParam String pw, @RequestParam String name, @RequestParam String tel) {
MemberVO vo = new MemberVO(-1, id, pw, name, tel);
if (service.insert(vo) == 1)
return "redirect:m_selectAll";
else
return "redirect:m_insert";
}
spring.thymeleaf.view-names=thymeleaf/*
spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.suffix=.html
thymeleaf 밑의 .html 파일을 자동으로 가져온다.thymeleaf: pom.xml에 추가하여 사용하는 html 템플릿이다. vue.js 등 다른 프레임워크를 사용하면 필요없다.
[[${변수} | ${#자체객체}]]로 쓰면 model의 변수 접근 가능. $ 대신 *도 가능하다.
<body>
<!-- thymeleaf폴더명/th_top_menu확장자뺀파일명 :: test_top_menu조각명 -->
<div th:insert="thymeleaf/th_top_menu :: test_top_menu"></div>
<h3>타임리프 템플릿 top_menu - insert는 현재 태그(div)를 유지하면서 템플릿 조각(test_top_menu)을 가져오는 방법</h3>
<h3>타임리프 템플릿 부가 설명은 하단에 푸터에서 확인할것.</h3>
<hr>
<h3>Model 받기( ${} or *{} 모두사용가능)</h3>
<p>
<span>[[${to_day}]]</span><br>
<span>[[*{to_day}]]</span><br>
<span th:text="${to_day}">thymeleaf안될때 기본값</span><br>
</p>
<p>
<span>[[${#dates}]]</span><br>
<span>[[${#dates.format(to_day)}]]</span>
</p>
<p>
<span>[[${#dates.format(to_day, 'yyyy/MM/dd/ HH:mm:ss')}]]</span>
</p>
<hr>
<h3>th:obejct</h3>
<div th:obejct="${vo}">
<span th:text="*{vo.num}">num</span>
<span th:text="*{vo.id}">id</span>
<span th:text="${vo.pw}">pw</span>
<span th:text="${vo.name}">name</span>
<span th:text="${vo.tel}">tel</span>
</div>
<hr>
<h3>변수할당</h3>
<ul th:with="kor=100, eng=99, math=88, name=kim">
<li><span>[[${kor}]]</span></li>
<li><span>[[${eng}]]</span></li>
<li><span>[[${math}]]</span></li>
<li><span>[[${name}]]</span></li>
</ul>
<hr>
<h3>th:href |...| : + 혹은 () 등으로 이어줘야 하는 것을 대신해서 | | 사이는 정보는 전부 문자열로 처리</h3>
<!-- |...| : + 혹은 () 등으로 이어줘야 하는 것을 대신해서 | | 사이는 정보는 전부 문자열로 처리 -->
<ul>
<li><a th:href="@{m_selectOne?num=}+${vo.num}"><span>[[${vo.num}]] 불편 ㅜㅜ</span></a></li>
<li><a th:href="@{m_selectOne(num=${vo.num})}"><span>[[${vo.num}]] 가독성 ㅜㅜ</span></a></li>
<li><a th:href="|m_selectOne?num=${vo.num}|"><span>[[${vo.num}]] 아주좋아</span></a></li>
</ul>
<hr>
<h3>Math.random()</h3>
<ul th:with="avg=99.99">
<li th:with="random_su=${T(java.lang.Math).random()}"><span>[[${random_su}]]</span></li>
<li th:with="random_su=${T(java.lang.Math).random()*10}"><span>[[${random_su}]]</span></li>
<li th:with="int_su=${T(java.lang.Math).floor(3.14)}"><span>[[${int_su}]]</span></li>
<li th:with="int_su=${T(java.lang.Math).floor(avg)}"><span>[[${int_su}]]</span></li>
<!-- 지역변수의 스코프는 선언된 해당 태그까지만이다 -->
<li th:with="random_su=${T(java.lang.Math).random()*10}">
<span th:with="int_su=${random_su}">[[${int_su}]]</span>
</li>
</ul>
<hr>
<h3>반복문 th:each</h3>
<ul>
<th:block th:each="num : ${#numbers.sequence(1,5)}">
<li><span>[[${num}]]</span></li>
</th:block>
</ul>
<hr>
<h3>분기문 th:if</h3>
<ul>
<th:block th:each="num : ${#numbers.sequence(1,5)}">
<li th:if="${num}%2==0"><span>[[${num}]]</span></li>
</th:block>
</ul>
<hr>
<h3>타임리프 템플릿 footer - insert는 현재 태그(div)를 유지하면서 템플릿 조각(footer)을 가져오는 방법</h3>
<div th:insert="thymeleaf/th_footer :: test_copy"></div>
<hr>
<h3>타임리프 템플릿 footer - replace는 현재 태그(div)를 버리고 템플릿 조각(footer)으로 덮어쓰는 방법</h3>
<div th:replace="thymeleaf/th_footer :: test_copy"></div>
<hr>
<h3>타임리프 템플릿 footer - replace + 함수를 통해 파라메터 전달 가능.</h3>
<div th:replace="thymeleaf/th_footer :: test_copyParam('SDS','010-1234-1234')"></div>
</body>
random_su 이런건 다 변수고, 형제 요소 끼리는 접근 불가능하다. 부모 요소의 변수는 접근할 수 있다.each를 이용하면 반복문 돌 수 있다.<body>
<div th:replace="thymeleaf/th_top_menu :: test_top_menu"></div>
<div th:replace="thymeleaf/th_content :: common_content('th_content01')"></div>
<div th:replace="${content} :: common_content('th_content01')"></div>
</body>
replace: th_top_ment.html의 th:fragment="th_top_menu" 요소가 있는 html 태그를 통째로 바꾼다.replace: th_content.html의 commom_content 변수에 th_content01을 넣어서 대체한다. replace: model에서 받은 content 변수로 처리해달라는 뜻@Mapper
public interface MemberMapper { // interface임에 주의
//sqlMapper_member.xml 문서에서의 (id="insertOK")와 insertOK()메소드 명이 같아짐으로 인해서
//@Repository 컴포넌트가 필요없어지게된다.
//즉, DAO,DAOimpl 이 없어도 동작한다.
public int insertOK(MemberVO vo);
public int updateOK(MemberVO vo);
public int deleteOK(MemberVO vo);
public MemberVO selectOne(MemberVO vo);
public List<MemberVO> selectAll();
public List<MemberVO> searchList(Map<String, String> map);
}
@Mapper 가 있으면 이때까지 했던 DAO, DAOimpl이 없어도 된다. Service가 impl의 역할을 한다. #DataSource 설정 : mysql 세팅
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/sds?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=1234
#connection-timeout : default 30000(30초)
#maximum-pool-size : default 10
spring.datasource.hikari.connection-timeout=60000
spring.datasource.hikari.maximum-pool-size=5
#1) connection-timeout (default : 30000 (30 seconds))
#클라이언트가 pool에 connection을 요청하는데 기다리는 최대시간을 설정합니다.
#설정한 시간을 초과하면 SQLException이 발생합니다. (허용 가능한 최소 연결 시간은 250ms )
#
#
#2) maximum-pool-size (default : 10)
#유휴 및 사용중인 connection을 포함하여 풀에 보관가능한 최대 커넥션 개수를 설정합니다.
#사용할 수 있는 커넥션이 없다면 connectionTimeout 시간 만큼 대기하고 시간을 초과하면 SQLException이 발생합니다.
#
#
#3) minimumIdle (default : maximumPoolSize와 동일)
#connection pool에서 유지가능한 최소 커넥션 개수를 설정합니다.
#최적의 성능과 응답성을 원하면 이 값을 설정하지 않는게 좋다고 합니다.
#
#
#4) idleTimeout (default : 600000 (10분))
#connection pool에서 유휴 상태로 유지시킬 최대 시간을 설정합니다.
#이 설정은 minimumIdle이 maximumPoolSize보다 작은 경우에만 사용할 수 있습니다.
#pool에 있는 connection이 minimumIdle에 도달할 경우 이후에 반환되는 connection에 대해서 바로 반환하지 않고 idleTimeout 만큼 유휴 상태로 있다가 폐기됩니다.
#
#
#5) maxLifeTime (default : 1800000 (30분))
#connection의 maxLifeTime 지났을 때, 사용중인 connection은 바로 폐기되지않고 작업이 완료되면 폐기됩니다.
#하지만 유휴 커넥션은 바로 폐기됩니다.
#maxLifeTime 설정은, db의 wait_timeout 보다 2~3초 짧게 주자. 좀더 여유있게 준다면 5초 정도 짧게 주면 된다.
#https://pkgonan.github.io/2018/04/HikariCP-test-while-idle
#
#
#6) readOnly (default : false)
#pool에서 얻은 connection이 기본적으로 readOnly인지 지정하는 설정입니다.
#데이터베이스가 readOnly 속성을 지원할 경우에만 사용할 수 있습니다.
#
#
#7) connectionTestQuery (default : none)
#데이터베이스 연결이 여전히 활성화되어있는지 확인하기 위해 pool에서 connection을 제공하기 전에 실행되는 쿼리입니다.
#드라이버가 JDBC4를 지원하는 경우 이 속성을 사용하지 않는 것이 좋다고합니다.
#위 설정 이외에도 많은 DBCP 설정을 제공합니다. 확인 하려면 아래 링크를 이용해주세요.
logging.level.org.hibernate.SQL=debug
logging.level.=error
mybatis.mapper-locations=classpath:/jdbc/sqlMapper_*.xml
sqlMapper_*.xml 파일에 설정해둔 대로 들어가고, 여기다가 SQL문도 다 쓸 수 있다.<!-- sqlMapper_member.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"https://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.demo.mapper.MemberMapper">
<select id="selectAll" resultType="com.example.demo.MemberVO">
select * from member order by num desc
</select>
<select id="selectOne" resultType="com.example.demo.MemberVO">
select * from member where num=#{num}
</select>
<select id="searchList" resultType="com.example.demo.MemberVO">
select * from member
<if test="searchKey == 'name'">
where name like #{searchWord} order by num desc
</if>
<if test="searchKey == 'tel'">
where tel like #{searchWord} order by num desc
</if>
</select>
<insert id="insertOK" parameterType="com.example.demo.MemberVO">
insert into member(id,pw,name,tel)
values(#{id},#{pw},#{name},#{tel})
</insert>
<update id="updateOK" parameterType="com.example.demo.MemberVO">
update member set id=#{id},pw=#{pw},name=#{name},tel=#{tel}
where num=#{num}
</update>
<delete id="deleteOK" parameterType="com.example.demo.MemberVO">
delete from member where num=#{num}
</delete>
</mapper>