- 어제와 마찬가지로 게시글 등록, 파일 업로드 등을 해보도록 하겠다.
- 테이블에서 DB와 user 생성을 확인한다.
- go to mysql
# 2021.10.14
create user 'product'@'localhost' identified by 'pass';
create database productdb;
grant all privileges on productdb.* to 'product'@'localhost';
- productDB에 아래와 같은 테이블을 만들어준다.
#2021.10.14
create table tbl_product(
pcode char(4) primary key not null,
pname nvarchar(200) not null,
price int default 0,
image nvarchar(200)
);
desc tbl_product;
insert into tbl_product(pcode, pname, price, image)
values('P110', '[14k Gold] 스테디 원터치 링귀걸이', 99900, 'img01.jpg');
insert into tbl_product(pcode, pname, price, image)
values('P111', '[14kGold] 델리아 원터치 링귀걸이', 69900, 'img02.jpg');
insert into tbl_product(pcode, pname, price, image)
values('P112', '[925실버] 샤인모션 원터치 링귀걸이', 20900, 'img03.jpg');
insert into tbl_product(pcode, pname, price, image)
values('P113', '[925실버] 볼앤하트 원터치 링귀걸이', 17900, 'img04.jpg');
insert into tbl_product(pcode, pname, price, image)
values('P114', '[14kGold] 셔링 귀걸이', 49900, 'img05.jpg');
insert into tbl_product(pcode, pname, price, image)
values('P115', '[14kGold] 메르시 목걸이', 15900, 'img06.jpg');
insert into tbl_product(pcode, pname, price, image)
values('P116', '[925실버] 트윈 원터치 링귀걸이', 20800, 'img07.jpg');
insert into tbl_product(pcode, pname, price, image)
values('P117', '[14kGold] 한쪽 베이직 금볼 귀걸이', 7900, 'img08.jpg');
create table tbl_attach(
image nvarchar(200) primary key not null,
pcode char(4),
foreign key(pcode) references tbl_product(pcode)
);
- C:\data\product 해당 경로에 테이블에서 insert한 이미지가 들어가 있는지 확인하고 없으면 넣어주자.
- 스프링과 DB연결 유저 설정 및 파일 업로드 경로 확인
/ex08/src/main/webapp/WEB-INF/spring/root-context.xml
.....
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="net.sf.log4jdbc.sql.jdbcapi.DriverSpy"></property>
<property name="url" value="jdbc:log4jdbc:mysql://127.0.0.1:3306/productdb"></property>
<property name="username" value="product"></property>
<property name="password" value="pass"></property>
</bean>
.....
/ex08/src/main/webapp/WEB-INF/spring/appServlet/servlet-context.xml
.....
<!-- 파일 업로드 루트 설정 -->
<beans:bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<beans:property name="maxUploadSize" value="10485760" />
</beans:bean>
<beans:bean id="uploadPath" class="java.lang.String">
<beans:constructor-arg value="c:/data/product" />
</beans:bean>
</beans:beans>
- SQL 문 실행을 위한 mapper 생성하겠다.
/ex08/src/main/resources/mapper/ProductMapper.xml
<?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="com.example.mapper.ProductMapper">
<select id="list" resultType="com.example.domain.ProductVO">
select * from tbl_product order by pcode desc limit 0,8
</select>
<insert id="insert">
insert into tbl_product(pcode, pname, image, price)
values(#{pcode},#{pname},#{image},#{price})
</insert>
<select id="read" resultType="com.example.domain.ProductVO">
select * from tbl_product where pcode=#{pcode}
</select>
<update id="update">
update tbl_product set pname=#{pname},image=#{image},price=#{price}
where pcode=#{pcode}
</update>
<delete id="delete">
delete from tbl_product where pcode=#{pcode}
</delete>
</mapper>
- 출력 타입인 VO를 생성하겠다.
/ex08/src/main/java/com/example/domain/ProductVO.java
package com.example.domain;
import java.util.ArrayList;
import com.fasterxml.jackson.annotation.JsonFormat;
public class ProductVO {
private String pcode;
private String pname;
private int price;
private String image;
// 멀티 이미지
private ArrayList<String> images;
... getter, setter, tostring
- 인터페이스 생성한다.
/ex08/src/main/java/com/example/mapper/ProductDAO.java
package com.example.mapper;
import java.util.List;
import com.example.domain.ProductVO;
public interface ProductDAO {
public List<ProductVO> list();
public void insert(ProductVO vo);
public void update(ProductVO vo);
public void delete(String pcode);
public ProductVO read(String pcode);
}
- 인터페이스를 메서드를 오버라이드하라 임플리먼트를 생성한다.
/ex08/src/main/java/com/example/mapper/ProductDAOImpl.java
package com.example.mapper;
import java.util.List;
import org.apache.ibatis.session.SqlSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import com.example.domain.ProductVO;
@Repository
public class ProductDAOImpl implements ProductDAO {
@Autowired
SqlSession session;
// mapper와의 연결을 위한 변수
String namespace = "com.example.mapper.ProductMapper";
@Override
public List<ProductVO> list() {
return session.selectList(namespace + ".list");
}
@Override
public void insert(ProductVO vo) {
session.insert(namespace + ".insert", vo);
}
@Override
public void update(ProductVO vo) {
session.update(namespace + ".update", vo);
}
@Override
public void delete(String pcode) {
session.delete(namespace + ".delete", pcode);
}
@Override
public ProductVO read(String pcode) {
return session.selectOne(namespace+".read", pcode);
}
}
- 파일 업로드할 sql 문을 작성하겠다.
/ex08/src/main/resources/mapper/AttachMapper.xml
<?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="com.example.mapper.AttachMapper">
<select id="list" resultType="string">
select * from tbl_attach where pcode=#{pcode}
</select>
<insert id="insert">
insert into tbl_attach(pcode,image)
values(#{pcode},#{image})
</insert>
<delete id="delete">
delete from tbl_attach
where image=#{image}
</delete>
</mapper>
/ex08/src/main/java/com/example/mapper/AttachDAO.java
package com.example.mapper;
import java.util.List;
public interface AttachDAO {
public List<String> list(String pcode);
public void insert(String pcode, String image);
public void delete(String image);
}
/ex08/src/main/java/com/example/mapper/AttachDAOImpl.java
package com.example.mapper;
import java.util.HashMap;
import java.util.List;
import org.apache.ibatis.session.SqlSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
@Repository
public class AttachDAOImpl implements AttachDAO {
@Autowired
SqlSession session;
String namespace = "com.example.mapper.AttachMapper";
@Override
public List<String> list(String pcode) {
return session.selectList(namespace + ".list", pcode);
}
@Override
public void insert(String pcode, String image) {
HashMap<String, Object> map = new HashMap<>();
map.put("image", image);
map.put("pcode", pcode);
session.insert(namespace + ".insert", map);
}
@Override
public void delete(String image) {
session.delete(namespace + ".delete", image);
}
}
- 메인페이지를 만들겠다.
- 이전에 사용했던 아래의 데이터를 해당 프로젝트에 넣어준다.
/ex08/src/main/webapp/WEB-INF/views/home.jsp
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ page session="false"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<html>
<head>
<title>Home & Shopping</title>
<link rel="stylesheet" href="/resources/home.css" />
<script src="http://code.jquery.com/jquery-3.1.1.min.js"></script>
<script
src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/3.0.1/handlebars.js"></script>
</head>
<body>
<div id="page">
<div id="header">
<a href="/" title="홈으로"><img src="/resources/back.png" width=960 /></a>
</div>
<div id="center">
<div id="menu">
<a href="/insert" title="상품등록">상품등록</a>
</div>
<div id="content"></div>
</div>
<div id="footer">
<h3>Copyright H&S. All rights Reserved.</h3>
</div>
</div>
</body>
</html>
- 이제 #content에 넣을 페이지를 만들겠다.
- 우선 컨트롤러를 생성하겠다.
/ex08/src/main/java/com/example/controller/ProductController.java
package com.example.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.example.domain.ProductVO;
import com.example.mapper.ProductDAO;
@Controller
public class ProductController {
@Autowired
ProductDAO pdao;
@RequestMapping("/list.json")
@ResponseBody
public List<ProductVO> list(){
return pdao.list();
}
}
- 이 json 을 list page에 출력하겠다.
/ex08/src/main/webapp/WEB-INF/views/list.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<style>
#products {
margin : 0px auto;
width: 900px;
overflow: hidden;
}
.box {
width: 200px;
height:200px;
float: left;
border: 1px solid rgb(224, 224, 235);
margin: 5px;
padding: 5px;
box-shadow:5px 5px 5px gray;
}
.pname{
text-overflow:ellipsis;
white-space:nowrap;
overflow: hidden;
}
img{
cursor: pointer;
}
</style>
<h1>[상품 목록]</h1>
<div id="products"></div>
<script id="temp" type="text/x-handlebars-template">
{{#each .}}
<div class="box">
<img src="/display?fileName={{image}}" width=150
onClick="location.href='read?pcode={{pcode}}'"/>
<div class="pname">{{pname}}</div>
<div class="price">{{price}}</div>
</div>
{{/each}}
</script>
<script>
getList();
function getList() {
$.ajax({
type : 'get',
url : '/list.json',
dataType : 'json',
success : function(data) {
var temp = Handlebars.compile($('#temp').html());
$('#products').html(temp(data));
}
});
}
</script>
/ex08/src/main/java/com/example/controller/HomeController.java
package com.example.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@Controller
public class HomeController {
@RequestMapping(value = "/", method = RequestMethod.GET)
public String home(Model model) {
model.addAttribute("pageName", "list.jsp");
return "home";
}
}
/ex08/src/main/webapp/WEB-INF/views/home.jsp
....
<div id="content">
<jsp:include page="${pageName}"></jsp:include>
</div>
....
/ex07/src/main/java/com/example/controller/ProductController.java
package com.example.controller;
import java.io.File;
import java.nio.file.Files;
import java.util.List;
import javax.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import com.example.domain.ProductVO;
import com.example.mapper.AttachDAO;
import com.example.mapper.ProductDAO;
@Controller
public class ProductController {
@Autowired
ProductDAO pdao;
@Autowired
AttachDAO adao;
// 파일 저장 루트 지정
@Resource(name = "uploadPath")
private String path;
@RequestMapping("/list.json")
@ResponseBody
public List<ProductVO> list() {
return pdao.list();
}
// 이미지파일 브라우저에 출력
@RequestMapping("/display")
@ResponseBody
public ResponseEntity<byte[]> display(String fileName) throws Exception {
ResponseEntity<byte[]> result = null;
// display fileName이 있는 경우
if (!fileName.equals("")) {
File file = new File(path + File.separator + fileName);
HttpHeaders header = new HttpHeaders();
header.add("Content-Type", Files.probeContentType(file.toPath()));
result = new ResponseEntity<>(FileCopyUtils.copyToByteArray(file), header, HttpStatus.OK);
}
return result;
}
}
- 이제 컨트롤러에 입력 페이지를 연결해주도록 하겠다.
/ex07/src/main/java/com/example/controller/ProductController.java
.....
// 파일 저장 루트 지정
@Resource(name = "uploadPath")
private String path;
// insert
@RequestMapping("/insert")
public String insert(Model model){
model.addAttribute("pageName","insert.jsp");
return "home";
}
.....
/ex08/src/main/webapp/WEB-INF/views/insert.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<h1>[상품 등록]</h1>
<style>
form {
overflow: hidden;
}
input[type=text]{
width: 100%;
margin: 10px 0px 10px 0px;
border: none;
border-bottom: 1px solid gray;
font-size: 20px;
}
input[type=file]{
margin: 10px 0px 10px 0px;
display: none;
}
</style>
<form name="frm" enctype="multipart/form-data">
<div>
<img src="http://placehold.it/350x300" id="image" width=300 />
</div>
<div>
<input type="text" name="pcode" readonly/>
<input type="text" name="pname" placeholder="상품명"/>
<input type="text" name="price" value="0" />
<input type="file" name="file"/>
</div>
<div>
<input type="submit" value="상품등록" />
<input type="reset" value="등록취소" />
</div>
</form>
- 상품코드를 테이블의 pcode 최대값을 구하여 넣어보겠다.
/ex07/src/main/resources/mapper/ProductMapper.xml
.....
<select id="maxCode" resultType="string">
select max(pcode) from tbl_product
</select>
.....
....
public String maxCode();
}
.....
@Override
public String maxCode() {
return session.selectOne(namespace+".maxCode");
}
}
/ex08/src/main/java/com/example/controller/ProductController.java
.....
// insert
@RequestMapping("/insert")
public String insert(Model model){
String maxCode=pdao.maxCode();
String pcode = "P"+(Integer.parseInt(maxCode.substring(1))+1);
model.addAttribute("pcode",pcode);
model.addAttribute("pageName","insert.jsp");
return "home";
}
....
/ex08/src/main/webapp/WEB-INF/views/insert.jsp
.....
<div>
<input type="text" name="pcode" value="${pcode}" readonly/>
<input type="text" name="pname" placeholder="상품명"/>
<input type="text" name="price" value="0" />
<input type="file" name="file"/>
</div>
......
- 이미지 클릭시 해당 이미지 태그가 변경될 수 있도록 하겠다.
/ex07/src/main/webapp/WEB-INF/views/insert.jsp
....
<script>
// 이미지 tag 클릭시
$('#image').on("click", function() {
$(frm.file).click();
})
// 이미지를 삽입하거나 변경시
$(frm.file).on("change", function(e) {
var file = $(this)[0].files[0];
$("#image").attr("src", URL.createObjectURL(file));
})
</script>
- 데이터 입력시 유효성 체크를 해보도록 하겠다.
/ex08/src/main/webapp/WEB-INF/views/insert.jsp
.....
<script>
// submit시 유효성 체크
$(frm).on("submit",function(e){
e.preventDefault();
var pcode = $(frm.pcode).val();
var pname = $(frm.pname).val();
var price = $(frm.price).val();
var file = $(frm.file).val();
if(pcode==""||pname==""||price==""||file==""){
alert("입력란을 확인해주세요.");
return;
}
if (price == '' || price.replace(/[0-9]/g, '')) {
alert('가격을 숫자로 입력하세요.');
$(frm.price).focus();
return;
}
if(!confirm("상품을 등록하시겠습니까?"))return;
frm.action="insert"
frm.method="post"
frm.submit();
});
.....
- 컨트롤러에서 post해줄 수 있도록 하겠다.
/ex08/src/main/java/com/example/controller/ProductController.java
.....
// 파일 저장 루트 지정
@Resource(name = "uploadPath")
private String path;
// insert data
@RequestMapping(value="/insert", method=RequestMethod.POST)
public String insertPost(ProductVO vo, MultipartHttpServletRequest multi) throws Exception{
System.out.println(vo.toString());
// 대표이미지 업로드
MultipartFile file=multi.getFile("file");
String image = System.currentTimeMillis()+"_"+file.getOriginalFilename();
file.transferTo(new File(path+"/"+image));
vo.setImage(image);
// 데이터 입력
pdao.insert(vo);
return "redirect:/";
}
.....
- 이제 read page를 만들어 update할 수 있도록 하겠다.
- insert.jsp를 복사해서 read.jsp를 만들겠다.
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<h1>[상품 정보]</h1>
<style>
form {
overflow: hidden;
}
input[type=text]{
width: 100%;
margin: 10px 0px 10px 0px;
border: none;
border-bottom: 1px solid gray;
font-size: 20px;
}
input[type=file]{
margin: 10px 0px 10px 0px;
display: none;
}
</style>
<form name="frm" enctype="multipart/form-data">
<div>
<img src="/display?fileName=${vo.image}" id="image" width=300 />
</div>
<div>
<input type="text" name="pcode" value="${vo.pcode}" readonly/>
<input type="text" name="pname" value="${vo.pname}"/>
<input type="text" name="price" value="${vo.price}" />
<input type="file" name="file" accept="image/*"/>
</div>
<div>
<input type="submit" value="상품수정" />
<input type="reset" value="수정취소" />
</div>
</form>
<script>
// submit시 유효성 체크
$(frm).on("submit",function(e){
e.preventDefault();
var pcode = $(frm.pcode).val();
var pname = $(frm.pname).val();
var price = $(frm.price).val();
var file = $(frm.file).val();
if(pcode==""||pname==""||price==""||file==""){
alert("입력란을 확인해주세요.");
return;
}
if (price == '' || price.replace(/[0-9]/g, '')) {
alert('가격을 숫자로 입력하세요.');
$(frm.price).focus();
return;
}
if(!confirm("상품을 등록하시겠습니까?"))return;
frm.action="insert"
frm.method="post"
frm.submit();
});
// 이미지 tag 클릭시
$('#image').on("click", function() {
$(frm.file).click();
})
// 이미지를 삽입하거나 변경시
$(frm.file).on("change", function(e) {
var file = $(this)[0].files[0];
$("#image").attr("src", URL.createObjectURL(file));
})
</script>
/ex08/src/main/java/com/example/controller/ProductController.java
.....
// 파일 저장 루트 지정
@Resource(name = "uploadPath")
private String path;
// read page con // new
@RequestMapping("/read")
public String read(String pcode, Model model){
model.addAttribute("vo",pdao.read(pcode));
model.addAttribute("pageName","read.jsp");
return "home";
}
.....
- 수정해보자.
- 기존에 이미지를 바꾸지 않으면 기존 이미지가 그대로 들어가고 바꾼다면 바꾼 이미지 이름이 DB에 저장될 수 있도록 하겠다.
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<h1>[상품 정보]</h1>
<style>
form {
overflow: hidden;
}
input[type=text]{
width: 100%;
margin: 10px 0px 10px 0px;
border: none;
border-bottom: 1px solid gray;
font-size: 20px;
}
input[type=file]{
margin: 10px 0px 10px 0px;
display: none;
}
</style>
<form name="frm" enctype="multipart/form-data">
<div>
<img src="/display?fileName=${vo.image}" id="image" width=300 />
</div>
<div>
<input type="hidden" name="image" value="${vo.image}" style="display:none"/>
<input type="text" name="pcode" value="${vo.pcode}" readonly/>
<input type="text" name="pname" value="${vo.pname}"/>
<input type="text" name="price" value="${vo.price}" />
<input type="file" name="file" accept="image/*"/>
</div>
<div>
<input type="submit" value="상품수정" />
<input type="reset" value="수정취소" />
</div>
</form>
<script>
// submit시 유효성 체크
$(frm).on("submit",function(e){
e.preventDefault();
var pcode = $(frm.pcode).val();
var pname = $(frm.pname).val();
var price = $(frm.price).val();
var file = $(frm.file).val();
if(pcode==""||pname==""||price==""){
alert("입력란을 확인해주세요.");
return;
}
if (price == '' || price.replace(/[0-9]/g, '')) {
alert('가격을 숫자로 입력하세요.');
$(frm.price).focus();
return;
}
if(!confirm("상품을 수정하시겠습니까?"))return;
frm.action="update"
frm.method="post"
frm.submit();
});
// 이미지 tag 클릭시
$('#image').on("click", function() {
$(frm.file).click();
})
// 이미지를 삽입하거나 변경시
$(frm.file).on("change", function(e) {
var file = $(this)[0].files[0];
$("#image").attr("src", URL.createObjectURL(file));
})
</script>
/ex08/src/main/java/com/example/controller/ProductController.java
.....
// 파일 저장 루트 지정
@Resource(name = "uploadPath")
private String path;
// update data // new
@RequestMapping(value="update", method=RequestMethod.POST)
public String update(ProductVO vo,MultipartHttpServletRequest multi) throws Exception{
MultipartFile file = multi.getFile("file");
// 이미지가 바뀐 경우 기존 이미지 삭제 후 바뀐 이미지 입력
if(!file.isEmpty()){
new File(path+"/"+vo.getImage()).delete();
String image = System.currentTimeMillis()+"_"+file.getOriginalFilename();
file.transferTo(new File(path+"/"+image));
vo.setImage(image);
}
// 아니면 update
pdao.update(vo);
return "redirect:/";
}
.....
- 첨부이미지 보여주도록 하겠다.
/ex08/src/main/java/com/example/controller/ProductController.java
.....
.....
// read page con
@RequestMapping("/read")
public String read(String pcode, Model model){
model.addAttribute("vo",pdao.read(pcode));
model.addAttribute("attList",adao.list(pcode));
model.addAttribute("pageName","read.jsp");
return "home";
}
.....
/ex08/src/main/webapp/WEB-INF/views/read.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
.....
<form name="frm" enctype="multipart/form-data">
<div>
<img src="/display?fileName=${vo.image}" id="image" width=300 />
</div>
<div>
<input type="hidden" name="image" value="${vo.image}" style="display:none"/>
<input type="text" name="pcode" value="${vo.pcode}" readonly/>
<input type="text" name="pname" value="${vo.pname}"/>
<input type="text" name="price" value="${vo.price}" />
<input type="file" name="file" accept="image/*"/>
</div>
<div>
<input type="submit" value="상품수정" />
<input type="reset" value="수정취소" />
</div>
<hr/>
<div>
첨부파일 추가 <input type="file" name="attFile" style="display: inline ;"/>
</div>
<h4>첨부 이미지</h4>
<div id="images">
<c:forEach items="${attList}" var="image">
<div class="box">
<img src="/display?fileName=${image}"/>
<a href="">삭제</a>
</div>
</c:forEach>
</div>
</form>
.....
- 첨부파일을 추가할 경우 tbl_attach에 insert할 수 있도록 하겠다. ajax처리 하겠다.
/ex08/src/main/webapp/WEB-INF/views/read.jsp
.....
<script>
// 어떤 제품에 첨부파일을 넣을 것인지
var pcode = $(frm.pcode).val();
// 첨부파일을 추가할 경우
$(frm.attFile).on('change',function(){
var file=$(this)[0].files[0];
if(file==null) return;
if(!confirm("파일을 첨부하시겠습니까?")) return;
var formData = new FormData();
formData.append("file",file);
formData.append("pcode",pcode);
$.ajax({
type:'post',
url:'/attInsert',
data:formData,
processData:false,
contentType:false,
success:function(data){
alert(data);
}
})
});
.......
- 컨트롤러에서 insert할 수 있도록 하겠다.
/ex08/src/main/java/com/example/controller/ProductController.java
..
// 파일 저장 루트 지정
@Resource(name = "uploadPath")
private String path;
// 첨부 파일 추가
@RequestMapping(value="attInsert", method=RequestMethod.POST)
@ResponseBody
public String attInsert(String pcode, MultipartFile file) throws Exception{
// 첨부파일 업로드
File attPath = new File(path+"/"+pcode);
if(!attPath.exists()) {
attPath.mkdir(); // .mkdir ; 디렉토리 생성
}
String image = pcode+"/"+System.currentTimeMillis()+"_"+file.getOriginalFilename();
file.transferTo(new File(path+"/"+image));
// 첨부데이터 입력
adao.insert(pcode, image);
return image;
}
.....
- insert한 이미지가 바로 보일 수 있도록 하겠다.
/ex08/src/main/webapp/WEB-INF/views/read.jsp
...
// 어떤 제품에 첨부파일을 넣을 것인지
var pcode = $(frm.pcode).val();
// 첨부파일을 추가할 경우
$(frm.attFile).on('change',function(){
var file=$(this)[0].files[0];
if(file==null) return;
if(!confirm("파일을 첨부하시겠습니까?")) return;
var formData = new FormData();
formData.append("file",file);
formData.append("pcode",pcode);
$.ajax({
type:'post',
url:'/attInsert',
data:formData,
processData:false,
contentType:false,
success:function(data){
var str='<div class="box">'
str+='<img src="/display?fileName='+data+'"/>'
str+='<a href="'+data+'">삭제</a>'
str+='</div>'
$('#images').append(str);
}
})
});
...
- 이제 첨부파일을 삭제해보도록 하겠다.
.....
<div id="images">
<c:forEach items="${attList}" var="image">
<div class="box">
<img src="/display?fileName=${image}"/>
<a href="${image}">삭제</a>
</div>
</c:forEach>
</div>
</form>
<script>
// 어떤 제품에 첨부파일을 넣을 것인지
var pcode = $(frm.pcode).val();
// 첨부파일 삭제
$("#images").on('click','.box a',function(e){
e.preventDefault();
if(!confirm("첨부파일을 삭제하시겠습니까?"))return;
var image=$(this).attr("href");
$.ajax({
type:'post',
url:'/attDelete',
data:{image:image},
success:function(){
alert("삭제되었습니다.");
}
})
});
.....
/ex08/src/main/java/com/example/controller/ProductController.java
.....
// 파일 저장 루트 지정
@Resource(name = "uploadPath")
private String path;
// 첨부 파일 삭제
@RequestMapping(value="attDelete", method=RequestMethod.POST)
@ResponseBody
public void attDelete(String image){
adao.delete(image); // 테이블에서 삭제
new File(path+"/"+image).delete(); // 디스크에서 삭제
}
.....
- 삭제되면 view에서도 삭제되게 하겠다.
/ex08/src/main/webapp/WEB-INF/views/read.jsp
....
// 어떤 제품에 첨부파일을 넣을 것인지
var pcode = $(frm.pcode).val();
// 첨부파일 삭제
$("#images").on('click','.box a',function(e){
e.preventDefault();
if(!confirm("첨부파일을 삭제하시겠습니까?"))return;
var box=$(this).parent(); // new 삭제 경로
var image=$(this).attr("href");
$.ajax({
type:'post',
url:'/attDelete',
data:{image:image},
success:function(){
alert("삭제되었습니다.");
box.remove(); // new
}
})
});
....
- 이제 목록 페이징을 해보겠다.
/ex08/src/main/resources/mapper/ProductMapper.xml
....
<select id="list" resultType="com.example.domain.ProductVO">
select * from tbl_product
order by pcode desc limit #{pageStart},#{perPageNum}
</select>
....
/ex08/src/main/java/com/example/controller/ProductController.java
....
@RequestMapping("/list.json")
@ResponseBody
public List<ProductVO> list(Criteria cri) {
return pdao.list(cri);
}
....
/ex08/src/main/java/com/example/mapper/ProductDAO.java
....
public interface ProductDAO {
public List<ProductVO> list(Criteria cri);
....
/ex08/src/main/java/com/example/mapper/ProductDAOImpl.java
....
@Override
public List<ProductVO> list(Criteria cri) {
return session.selectList(namespace + ".list",cri);
}
....
/ex08/src/main/java/com/example/controller/ProductController.java
....
@RequestMapping("/list.json")
@ResponseBody
public HashMap<String, Object> list(Criteria cri) {
HashMap<String, Object> map = new HashMap<>();
cri.setPerPageNum(8);
map.put("cri", cri);
map.put("list", pdao.list(cri));
PageMaker pm = new PageMaker();
pm.setCri(cri);
pm.setTotalCount(pdao.totCount());
map.put("pm", pm);
return map;
}
....
/ex08/src/main/webapp/WEB-INF/views/list.jsp
....
<script id="temp" type="text/x-handlebars-template">
{{#each list}} <<<-------------------------------------------------------------
<div class="box">
<img src="/display?fileName={{image}}" width=150 height=150
onClick="location.href='read?pcode={{pcode}}'"/>
<div class="pcode">{{pcode}}</div>
<div class="pname">{{pname}}</div>
<div class="price">{{price}}</div>
</div>
{{/each}}
</script>
....
- 토탈 카운터 및 조건검색하겠다.
/ex08/src/main/resources/mapper/ProductMapper.xml
...
<select id="totCount" resultType="int">
select count(*) from tbl_product
</select>
...
/ex08/src/main/java/com/example/mapper/ProductDAO.java
public int totCount();
}
/ex08/src/main/java/com/example/mapper/ProductDAOImpl.java
@Override
public int totCount() {
return session.selectOne(namespace+".totCount");
}
}
/ex08/src/main/java/com/example/controller/ProductController.java
@RequestMapping("/list.json")
@ResponseBody
public HashMap<String, Object> list(Criteria cri) {
HashMap<String, Object> map = new HashMap<>();
cri.setPerPageNum(8);
map.put("cri", cri);
map.put("list", pdao.list(cri));
PageMaker pm = new PageMaker();
pm.setCri(cri);
pm.setTotalCount(pdao.totCount());
map.put("pm", pm);
return map;
}
/ex08/src/main/webapp/WEB-INF/views/list.jsp
....
<h1>[상품 목록]</h1>
<div id="condition">
<select name="" id="searchType">
<option value="pcode">상품코드</option>
<option value="pname">상품명</option>
</select> <input type="text" id="keyword" placeholder="검색어" /> 검색수 : <span
id="totCount"></span>
<hr />
</div>
<div id="products"></div>
<script id="temp" type="text/x-handlebars-template">
{{#each list}}
<div class="box">
<img src="/display?fileName={{image}}" width=150 height=150
onClick="location.href='read?pcode={{pcode}}'"/>
<div class="pcode">{{pcode}}</div>
<div class="pname">{{pname}}</div>
<div class="price">{{price}}</div>
</div>
{{/each}}
</script>
<div id="pagination" class="pagination"></div>
<script src="/resources/pagination.js"></script>
<script>
var page = 1;
getList();
function getList() {
var keyword = $('#keyword').val();
var searchType = $('#searchType').val();
$.ajax({
type : 'get',
url : '/list.json',
dataType : 'json',
data : {
page : page,
keyword : keyword,
searchType : searchType
},
success : function(data) {
var temp = Handlebars.compile($('#temp').html());
$('#products').html(temp(data));
$("#pagination").html(getPagination(data));
$("#totCount").html(data.pm.totalCount);
}
});
}
....
- 조건 검색을 위해 if tag 지정
/ex08/src/main/resources/mapper/ProductMapper.xml
...
<select id="list" resultType="com.example.domain.ProductVO">
select * from tbl_product
<if test="searchType=='pcode'">
where pcode like concat('%',#{keyword},'%')
</if>
<if test="searchType=='pname'">
where pname like concat('%',#{keyword},'%')
</if>
order by pcode desc
limit #{pageStart},#{perPageNum}
</select>
....
- 조건 검색에 따른 검색갯수 변하게 하겠다.
/ex08/src/main/resources/mapper/ProductMapper.xml
...
<select id="totCount" resultType="int">
select count(*) from tbl_product
<if test="searchType=='pcode'">
where pcode like concat('%',#{keyword},'%')
</if>
<if test="searchType=='pname'">
where pname like concat('%',#{keyword},'%')
</if>
</select>
...
/ex08/src/main/java/com/example/mapper/ProductDAO.java
public int totCount(Criteria cri);
}
/ex08/src/main/java/com/example/mapper/ProductDAOImpl.java
@Override
public int totCount(Criteria cri) {
return session.selectOne(namespace+".totCount",cri);
}
}
/ex08/src/main/java/com/example/controller/ProductController.java
...
@RequestMapping("/list.json")
@ResponseBody
public HashMap<String, Object> list(Criteria cri) {
HashMap<String, Object> map = new HashMap<>();
cri.setPerPageNum(8);
map.put("cri", cri);
map.put("list", pdao.list(cri));
PageMaker pm = new PageMaker();
pm.setCri(cri);
pm.setTotalCount(pdao.totCount(cri));<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<----
map.put("pm", pm);
return map;
}
...
- 조회수 카운터 해보겠다.
- go to mysql
# 뷰 카운터 컬럼 추가
alter table tbl_product add viewcnt int default 0;
alter table tbl_product add attachcnt int default 0;
- list.jsp 에 출력해보겠다.
/ex08/src/main/webapp/WEB-INF/views/list.jsp
...
<script id="temp" type="text/x-handlebars-template">
{{#each list}}
<div class="box">
<img src="/display?fileName={{image}}" width=150 height=150
onClick="location.href='read?pcode={{pcode}}'"/>
<div class="pcode">
<b>{{pcode}}</b>
<span class="viewcnt">조회수:{{viewcnt}}</span>
</div>
<div class="pname">{{pname}}</div>
<div class="price">{{price}}</div>
</div>
{{/each}}
</script>
...
/ex08/src/main/resources/mapper/ProductMapper.xml
<update id="viewcnt">
update tbl_product set viewcnt=viewcnt+1
where pcode=#{pcode}
</update>
public void viewcnt(String pcode);
}
@Override
public void viewcnt(String pcode) {
session.update(namespace+".viewcnt",pcode);
}
}
- 해당 작업은 두개 이상이니 서비스를 이용하겠다.
/ex08/src/main/java/com/example/service/ProductService.java
package com.example.service;
import com.example.domain.ProductVO;
public interface ProductService {
public ProductVO read(String pcode);
}
/ex08/src/main/java/com/example/service/ProductServiceImpl.java
package com.example.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.example.domain.ProductVO;
import com.example.mapper.ProductDAO;
@Service
public class ProductServiceImpl implements ProductService {
@Autowired
ProductDAO pdao;
@Transactional
@Override
public ProductVO read(String pcode) {
pdao.viewcnt(pcode);
return pdao.read(pcode);
}
}
- 이제 정보 read 시 service의 read를 이용하면 된다.
...
@Autowired
ProductService service;
...
// read page con
@RequestMapping("/read")
public String read(String pcode, Model model){
model.addAttribute("vo",service.read(pcode));
model.addAttribute("attList",adao.list(pcode));
model.addAttribute("pageName","read.jsp");
return "home";
}
...
- VO에 추가해주지 않고 viewcnt를 가지고 오기 위해서 list 반환타입을 hashmap으로 한다.
/ex08/src/main/resources/mapper/ProductMapper.xml
...
<select id="list" resultType="hashmap">
select * from tbl_product
<if test="searchType=='pcode'">
where pcode like concat('%',#{keyword},'%')
</if>
<if test="searchType=='pname'">
where pname like concat('%',#{keyword},'%')
</if>
order by pcode desc
limit #{pageStart},#{perPageNum}
</select>
...
- 이제 조건 정렬 해보겠다.
/ex08/src/main/webapp/WEB-INF/views/list.jsp
...
<div id="condition">
<select name="" id="searchType">
<option value="pcode">상품코드</option>
<option value="pname">상품명</option>
</select> <input type="text" id="keyword" placeholder="검색어" />
검색수 : <span id="totCount"></span>
<select id="orderType">
<option value="order1">인기상품순</option>
<option value="order2">최신상품순</option>
<option value="order3">높은가격순</option>
<option value="order4">낮은가격순</option>
</select>
<hr />
</div>
...
function getList() {
var keyword = $('#keyword').val();
var searchType = $('#searchType').val();
var orderType = $('#orderType').val();
$.ajax({
type : 'get',
url : '/list.json',
dataType : 'json',
data : {
page : page,
keyword : keyword,
searchType : searchType,
orderType : orderType
},
success : function(data) {
var temp = Handlebars.compile($('#temp').html());
$('#products').html(temp(data));
$("#pagination").html(getPagination(data));
$("#totCount").html(data.pm.totalCount);
}
});
}
...
/ex08/src/main/java/com/example/controller/ProductController.java
...
@RequestMapping("/list.json")
@ResponseBody
public HashMap<String, Object> list(Criteria cri, String orderType) {
HashMap<String, Object> map = new HashMap<>();
cri.setPerPageNum(8);
map.put("cri", cri);
map.put("list", pdao.list(cri, orderType));
PageMaker pm = new PageMaker();
pm.setCri(cri);
pm.setTotalCount(pdao.totCount(cri));
map.put("pm", pm);
return map;
}
...
/ex08/src/main/java/com/example/mapper/ProductDAO.java
public interface ProductDAO {
public List<ProductVO> list(Criteria cri, String orderType);
/ex08/src/main/java/com/example/mapper/ProductDAOImpl.java
@Override
public List<ProductVO> list(Criteria cri, String orderType) {
HashMap<String, Object> map = new HashMap<>();
map.put("cri", cri);
map.put("orderType", orderType);
return session.selectList(namespace + ".list",cri);
}
/ex08/src/main/resources/mapper/ProductMapper.xml
...
<select id="list" resultType="hashmap">
select * from tbl_product
<if test="cri.searchType=='pcode'">
where pcode like concat('%',#{cri.keyword},'%')
</if>
<if test="cri.searchType=='pname'">
where pname like concat('%',#{cri.keyword},'%')
</if>
<!-- 조건 정렬 -->
<if test="orderType=='order1'">
order by viewcnt desc
</if>
<if test="orderType=='order2'">
order by pcode desc
</if>
<if test="orderType=='order3'">
order by price desc
</if>
<if test="orderType=='order4'">
order by price
</if>
limit #{cri.pageStart},#{cri.perPageNum}
</select>
...
/ex08/src/main/webapp/WEB-INF/views/list.jsp
$('#orderType').on('change',function(){
page=1;
getList();
})
'ICIA 수업일지' 카테고리의 다른 글
2021.10.18 수업일지(Spring Framework, Interceptor) (0) | 2021.10.18 |
---|---|
2021.10.15 수업일지(Spring Framework, Fileupload, interceptor) (0) | 2021.10.15 |
2021.10.13 수업일지(Spring Framework, fileupload) (0) | 2021.10.13 |
2021.10.12 수업일지(Spring 연습, fileupload 방법 (0) | 2021.10.12 |
2021.10.08 수업일지(Spring Framework 연습) (0) | 2021.10.08 |