테이블 생성:
create table bootshop (num smallint primary key auto_increment,
sangpum varchar(30),
price int,
photoname varchar(50),
ipgoday datetime);
<!-- tomcat-embed-jasper -->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope>
</dependency>
<!-- jstl -->
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
#tomcat port
server:
port: 9001
#jsp
spring:
#mvc:
#view:
#prefix: /WEB-INF/
#suffix: .jsp
devtools:
livereload:
enabled: true
#mysql
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/sist?serverTimezone=Asia/Seoul
username: dragon
password: 1234
위처럼 필요한 컨트롤러, Dto, 인터페이스 등을 만들어준 후에 Dto를 만들어준다.
package mini.data.dto;
import java.sql.Timestamp;
import org.apache.ibatis.type.Alias;
import lombok.Data;
@Data
@Alias("bsdto")
public class BootShopDto {
private String num;
private String sangpum;
private String photoname;
private int price;
private Timestamp ipgoday;
}
@ComponentScan, @MapperScan 해주기
package com.example.demo;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;
@SpringBootApplication
@ComponentScan({"mini.data.*"})
@MapperScan("mini.data.*") //mini.data.mapper
public class SpringBootMiniProjectApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootMiniProjectApplication.class, args);
}
}
위에서 mapper를 등록해줬으니 BootShopSql.xml에서 mapper의 namespace를 적어줄 수 있다.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="mini.data.mapper.BootShopMapperInter">
</mapper>
@Mapper
public interface BootShopMapperInter {
public int getTotalCount();
public void insertBootShop(BootShopDto dto);
public List<BootShopDto> getAllList();
}
<select id="getTotalCount" resultType="int">
select count(*) from bootshop
</select>
<insert id="insertBootShop" parameterType="bsdto">
insert into bootshop (sangpum, price, photoname, ipgoday) values(#{sangpum},#{price},#{photoname},now())
</insert>
<select id="getAllList" resultType="bsdto">
select * from bootshop order by num desc
</select>
//처음 시작시 list
@GetMapping("/")
public String start() {
//return "redirect:bootshop/list";
return "/layout/main"; //tiles
}
@Controller
public class BootShopController {
@Autowired
BootShopMapperInter mapper;
//list 이동+전체 출력
@GetMapping("/bootshop/list")
public ModelAndView list() {
ModelAndView mview = new ModelAndView();
int totalCount = mapper.getTotalCount();
List<BootShopDto> list = mapper.getAllList();
mview.addObject("totalCount", totalCount);
mview.addObject("list", list);
//mview.setViewName("bootshop/shoplist"); //jsp
mview.setViewName("/bootshop/shoplist"); //tiles
return mview;
}
//addform 이동
@GetMapping("/bootshop/shopform")
public String form() {
return "/bootshop/addform";
}
//insert
@PostMapping("/bootshop/insert")
public String insert(@ModelAttribute BootShopDto dto,
@RequestParam MultipartFile upload,
HttpSession session) {
String path = session.getServletContext().getRealPath("/photo");
System.out.println(path);
if(upload.getOriginalFilename().equals(""))
dto.setPhotoname(null);
else {
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
String photoname="f_"+sdf.format(new Date())+upload.getOriginalFilename();
dto.setPhotoname(photoname);
try {
upload.transferTo(new File(path+"/"+photoname));
} catch (IllegalStateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//insert
mapper.insertBootShop(dto);
return "redirect:list";
}
<body>
<div class="alert alert-success" style="width: 800px;">
<b>총 ${totalCount }개의 상품이 있습니다.</b>
</div>
<table class="table table-bordered" style="width: 600px; margin: 30px;">
<caption><span><button type="button" class="btn btn-default" onclick="location.href='shopform'">상품 추가</button></span></caption>
<c:forEach var="dto" items="${list }" varStatus="i">
<tr>
<td width="230" rowspan="4">
<c:if test="${dto.photoname!=null }">
<img alt="" src="../photo/${dto.photoname}" style="width: 200px; height: 200px;">
</c:if>
<c:if test="${dto.photoname==null }">
<img alt="" src="../image/noimage.png" style="width: 200px; height: 200px;">
</c:if>
</td>
<td>
<b>상품명: ${dto.sangpum}</b>
</td>
</tr>
<tr>
<td>
<b>단가: <fmt:formatNumber value="${dto.price }" type="currency"/> </b>
</td>
</tr>
<tr>
<td>
<b>입고일: <fmt:formatDate value="${dto.ipgoday}" pattern="yyyy-MM-dd"/> </b>
</td>
</tr>
<tr>
<td>
<button type="button" class="btn btn-warning" onclick="location.href='updateform?num=${dto.num}'">수정</button>
<button type="button" class="btn btn-danger" onclick="location.href='delete?num=${dto.num}'">삭제</button>
</td>
</tr>
</c:forEach>
</table>
</body>
<script type="text/javascript">
function readURL(input) {
if (input.files && input.files[0]) {
var reader = new FileReader();
reader.onload = function (e) {
$('#uploadimg').attr('src', e.target.result);
}
reader.readAsDataURL(input.files[0]);
}
}
</script>
</head>
<body>
<form action="insert" method="post" enctype="multipart/form-data">
<table class="table table-bordered" style="width: 1000px; margin: 50px 50px;">
<caption><h3>상품 등록</h3></caption>
<tr bgcolor="pink">
<th style="width: 150px;">상품명</th>
<th style="width: 100px;">단가</th>
<th style="width: 250px;">이미지</th>
<th style="width: 350px;">미리보기</th>
</tr>
<tr>
<td>
<input type="text" class="form-control" name="sangpum" required="required">
</td>
<td>
<input type="text" class="form-control" name="price" required="required">
</td>
<td>
<input type="file" class="form-control" name="upload" onchange="readURL(this);">
</td>
<td>
<div style="margin: 20px 20px;">
<img id="uploadimg" src="" alt="상품 이미지를 등록해주세요" style="width: 150px; height: 150px;" />
</div>
</td>
</tr>
<tr>
<td colspan="5" align="center">
<button type="submit" class="btn btn-primary">등록하기</button>
<button type="button" class="btn btn-seconday" onclick="location.href='list'">목록으로</button>
</td>
</tr>
</table>
</form>
여기까진 지금까지 했던 것 반복.
이제부터는 layout으로 웹페이지를 구성한다.
<c:set var="root" value="<%=request.getContextPath() %>"></c:set>
절대경로를 미리 root로 지정해주면 경로를 줄 때 편하다.
<a href="/"><img alt="" src="${root}/image/title.png">
<br>
<b>SpringBoot+Mybatis+Tiles3</b>
</a>
<div style="font-size: 12pt; line-height: 25px;">
<span class="glyphicon glyphicon-user"></span>00교육센터<br>
<span class="glyphicon glyphicon-phone-alt"></span>02-1111-2222<br>
<span class="glyphicon glyphicon-map-marker"></span>서울시 강남구<br>
<span class="glyphicon glyphicon-envelope">ssss@naver.com</span><br>
<span class="glyphicon glyphicon-barcode"></span><br>
</div>
<c:set var="root" value="<%=request.getContextPath() %>"></c:set>
<body>
<ul class="nav nav-tabs menu">
<li class="nav-item">
<a class="nav-link active" href="${root}/">Home</a>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" data-bs-toggle="dropdown" href="#">상품</a>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="${root}/bootshop/shopform">상품 등록</a></li>
<li><a class="dropdown-item" href="${root}/bootshop/list">상품 목록</a></li>
</ul>
</li>
<li class="nav-item dropdown">
<a class="nav-link dropdown-toggle" data-bs-toggle="dropdown" href="#">회원</a>
<ul class="dropdown-menu">
<li><a class="dropdown-item" href="${root}/member/form">회원 가입</a></li>
<li><a class="dropdown-item" href="${root}/member/list">회원 목록</a></li>
</ul>
</li>
<li class="nav-item">
<a class="nav-link" href="${root}/board/list">게시판</a></li>
</li>
<li class="nav-item">
<a class="nav-link" href="${root}/load/map">오시는 길</a></li>
</li>
</ul>
</body>
<c:set var="root" value="<%=request.getContextPath() %>"></c:set>
<body>
<img alt="" src="${root }/image/toy04.png" width="300">
</body>
<!-- tiles-jsp -->
<dependency>
<groupId>org.apache.tiles</groupId>
<artifactId>tiles-jsp</artifactId>
<version>3.0.8</version>
</dependency>
<!-- tiles-el -->
<dependency>
<groupId>org.apache.tiles</groupId>
<artifactId>tiles-el</artifactId>
<version>3.0.8</version>
</dependency>
tiles 관련 dependency 추가(자동 완성 오류나는 경우 tiles api도 추가)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE tiles-definitions PUBLIC
"-//Apache Software Foundation//DTD Tiles Configuration 3.0//EN"
"http://tiles.apache.org/dtds/tiles-config_3_0.dtd">
<tiles-definitions>
<!-- #layout1 -->
<definition name="layout1" template="/WEB-INF/layout/layout1.jsp">
<put-attribute name="title" value="/WEB-INF/layout/title.jsp"/>
<put-attribute name="menu" value="/WEB-INF/layout/menu.jsp"/>
<put-attribute name="main" value="/WEB-INF/layout/main.jsp"/>
<put-attribute name="info" value="/WEB-INF/layout/info.jsp"/>
</definition>
<!-- wild card_#1 -->
<definition name="/*/*" extends="layout1">
<put-attribute name="main" value="/WEB-INF/{1}/{2}.jsp"/>
</definition>
definition: layout을 어떻게 만들지 정의한다.
name을 다르게 설정해주면 layout을 각각 다르게 만들어서 보이게 할 수 있다.
template="/WEB-INF/layout/layout1.jsp": layout1이 어디인지 경로를 지정해준다.
put-attribute name="title" value="/WEB-INF/layout/title.jsp": layout에 title을 넣겠다는 뜻
wild card: 전에는 board/list, board/addform... 이런식으로 썼는데 이걸 다 쓰기엔 힘드니까 와일드 카드를 사용해준다.
put-attribute name="main" value="/WEB-INF/{1}/{2}.jsp": main에 내용을 출력할 것이기 때문에 name="main"으로 준다. value 값은 "/WEB-INF/{폴더명}/{파일명}.jsp"로 주었기 때문에 와일드 카드의 name을 //로 준다. (굳이 앞에 /를 주는 이유는 layout이 여러개이기 때문이다)
위에 taglib을 꼭 추가해줘야 한다.
<%@ taglib uri="http://tiles.apache.org/tags-tiles" prefix="tiles" %>
<body>
<div class="layout">
<div class="title">
<tiles:insertAttribute name="title"/>
</div>
<div class="menu">
<tiles:insertAttribute name="menu"/>
</div>
<div class="info">
<tiles:insertAttribute name="info"/>
</div>
<div class="main">
<tiles:insertAttribute name="main"/>
</div>
</div>
</body>
package com.example.demo;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.view.UrlBasedViewResolver;
import org.springframework.web.servlet.view.tiles3.SimpleSpringPreparerFactory;
import org.springframework.web.servlet.view.tiles3.TilesConfigurer;
import org.springframework.web.servlet.view.tiles3.TilesView;
import org.springframework.web.servlet.view.tiles3.TilesViewResolver;
@Configuration
public class TilesConfig {
@Bean
public TilesConfigurer tilesConfigurer() {
System.out.println("tiles");
TilesConfigurer tilesConfigurer = new TilesConfigurer();
tilesConfigurer.setDefinitions(new String[] {"/WEB-INF/tiles.xml"});
tilesConfigurer.setCheckRefresh(true);
//ViewPreparer에서 Autowired가 가능하게 하는 설정
tilesConfigurer.setPreparerFactoryClass(SimpleSpringPreparerFactory.class);
return tilesConfigurer;
}
@Bean
public TilesViewResolver tilesViewResolver() {
TilesViewResolver viewResolver = new TilesViewResolver();
viewResolver.setViewClass(TilesView.class);
viewResolver.setOrder(1);
return viewResolver;
}
@Bean
public UrlBasedViewResolver viewResolver() {
final UrlBasedViewResolver resolver = new UrlBasedViewResolver();
resolver.setViewClass(TilesView.class);
resolver.setOrder(1);
return resolver;
}
}
tilesConfig까지 넣어주고 실행하면 된다.
이제 다른 layout을 만들어보자.
<body>
<h2 class="alert alert-info">00 교육센터 강남</h2>
<iframe src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d3165.366002049731!2d127.03101211537782!3d37.499284979810504!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x357ca1c32408f9b7%3A0x4e3761a4f356d1eb!2z7IyN7Jqp6rWQ7Jyh7IS87YSw!5e0!3m2!1sko!2skr!4v1667802146804!5m2!1sko!2skr" width="600" height="450" style="border:0;" allowfullscreen="" loading="lazy" referrerpolicy="no-referrer-when-downgrade"></iframe>
</body>
map.jsp를 출력하는 layout2를 만들어보자.
taglib 추가!
<%@ taglib uri="http://tiles.apache.org/tags-tiles" prefix="tiles" %>
<body style="background-color: pink">
<div class="layout">
<div class="menu">
<tiles:insertAttribute name="menu"/>
</div>
<div class="main">
<tiles:insertAttribute name="main"/>
</div>
</div>
</body>
<!-- #layout2 -->
<definition name="layout2" template="/WEB-INF/layout/layout2.jsp">
<put-attribute name="menu" value="/WEB-INF/layout/menu.jsp" />
<put-attribute name="main" value="/WEB-INF/layout/map.jsp"/>
</definition>
<!-- wild card#2 -->
<definition name="/sub/*/*" extends="layout2">
<put-attribute name="main" value="/WEB-INF/{1}/{2}.jsp"></put-attribute>
</definition>
put-attribute name="main" value="/WEB-INF/layout/map.jsp": main 부분에 map.jsp를 출력하겠다는 뜻
//map 나오게
@GetMapping("/load/map")
public String map() {
return "/sub/layout/map";
}