|
Back-End/Spring 2019. 6. 21. 12:18
- JFreeChart 만들기 -
참고 사이트 : http://www.jfree.org/jfreechart/
JFreeChart의 특징
다양한 형태의 차트 지원
Swing, JSP, Servlet 에서 많이 사용되고 있음
pdf 또는 png, jpg 등의 다양한 이미지 파일 형식으로 export 가능
오픈 소스 라이브러리
|
pom.xml에 라이브러리를 추가 | .<!-- https://mvnrepository.com/artifact/org.jfree/jfreechart --> <dependency> <groupId>org.jfree</groupId> <artifactId>jfreechart</artifactId> <version>1.5.0</version> </dependency> | cs |
두가지 형식으로 만들기
JFreeChart (png) : 미리 차트를 만들어서 png파일 (이미지파일) 로 출력시킴 (뷰 => 컨트롤러 => 서비스,서비스구현 => 컨트롤러(바로출력))
JFreeChart (pdf) : 미리 차트를 만들어서 pdf 파일로 만들어주고, 그 파일을 출력함 (뷰 => 컨트롤러 =>서비스,서비스구현 => 컨트롤러 => 뷰) (pdf 만드는 법은 itextpdf를 사용하는 방법을 써서 만듦)
컨트롤러, 서비스 , 서비스구현 클래스 만들어서 사용
admin_menu.jsp 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | .<!-- 메뉴 링크를 추가하고 PDF리스트로 갈수있는 링크도 추가 --> <a href="${path}/pdf/list.do">PDF</a> ㅣ <a href="${path}/chart/chart1.do">구글차트(json)</a> ㅣ <a href="${path}/chart/chart2.do">구글차트(db)</a> ㅣ <a href="${path}/jchart/chart2.do">JFreeChart(png)</a> ㅣ <a href="${path}/jchart/chart2.do">JFreeChart(pdf)</a> ㅣ <a href="${path}/email/write.do">이메일 발송</a> ㅣ <a href="${path}/shop/product/list.do">상품목록</a> ㅣ <a href="${path}/shop/product/write.do">상품등록</a> ㅣ | cs |
JFreeChartController.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | .package com.example.spring02.controller.chart; import java.io.FileOutputStream; import javax.inject.Inject; import javax.servlet.http.HttpServletResponse; import org.jfree.chart.ChartUtils; import org.jfree.chart.JFreeChart; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.servlet.ModelAndView; import com.example.spring02.service.chart.JFreeChartService; import com.itextpdf.text.Document; import com.itextpdf.text.Image; import com.itextpdf.text.pdf.PdfWriter; @Controller public class JFreeChartController { @Inject JFreeChartService chartService; //서비스를 호출해야하기 때문에 서비스에 의존성 주입 @RequestMapping("chart1.do")//view에서 맵핑되는 메소드 public void createChart1(HttpServletResponse response){ //화면에 바로 출력을 해야하기 때문에 HttpServletResponse를 사용 try { JFreeChart chart = chartService.createChart(); //서비스에서 생성한 차트를 받아와 변수에 저장, 차트를 얻어온다음에 바로 이미지파일로 보냄 ChartUtils.writeChartAsPNG(response.getOutputStream(), chart, 900, 550); //차트를 받아와서 가로, 세로 길이를 설정해준다. view 필요없이 화면에 곧바로 출력이 된다. } catch (Exception e) { e.printStackTrace(); } } @RequestMapping("chart2.do") //view에서 맵핑되는 메소드, pdf를 만들때 사용되는 메소드 public ModelAndView createChart2(HttpServletResponse response) { String message = ""; try { JFreeChart chart = chartService.createChart(); //서비스로부터 차트를 가져옴 Document document = new Document(); //웹 페이지에 접근할수 있는 객체를 생성 PdfWriter.getInstance(document, new FileOutputStream("d:/test.pdf")); //pdf파일 저장될 경로 //pdf 파일로 변환하기 위한 과정 document.open(); //pdf파일을 연다 Image png = Image.getInstance( ChartUtils.encodeAsPNG(chart.createBufferedImage(500, 500))); //차트의 내용을 500 x 500 이미지로 만들기 document.add(png); //만든 이미지를 pdf 파일에 저장 document.close(); //저장을 했으니 파일을 닫기 message = "pdf 파일이 생성되었습니다."; } catch (Exception e) { e.printStackTrace(); message = "pdf 파일 생성 실패..."; } return new ModelAndView("chart/jchart02","message",message); //보낼 페이지와 보낼 값을 지정해서 리턴한다. //jchart02 페이지에 값을 보내서 메시지를 출력한다. (pdf파일이 생성이 되었는지, 안되었는지..) } } | cs |
JFreeChartService.java | package com.example.spring02.service.chart; import org.jfree.chart.JFreeChart; public interface JFreeChartService { public JFreeChart createChart(); //JFreeChart를 만드는 추상메소드 } | cs |
JFreeChartServiceImpl.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 | .package com.example.spring02.service.chart; import java.util.List; import javax.inject.Inject; import org.jfree.chart.ChartFactory; import org.jfree.chart.JFreeChart; import org.jfree.chart.StandardChartTheme; import org.jfree.chart.plot.PlotOrientation; import org.jfree.data.category.DefaultCategoryDataset; import org.jfree.data.general.DefaultPieDataset; import org.springframework.stereotype.Service; import com.example.spring02.model.shop.dao.CartDAO; import com.example.spring02.model.shop.dto.CartDTO; import com.itextpdf.text.Font; import com.sun.prism.paint.Color; @Service public class JFreeChartServiceImpl implements JFreeChartService { @Inject CartDAO cartDao; //DAO를 호출하기 위해 의존성을 주입시킨다. @Override public JFreeChart createChart() { List<CartDTO> list = cartDao.cartMoney(); //Dao에 저장된 장바구니에 담은 금액을 리스트에 저장 //파이 차트가 아닌경우 //파이 차트일때와는 클래스가 틀리다. DefaultCategoryDataset dataset = new DefaultCategoryDataset(); for (CartDTO dto : list) { dataset.setValue(dto.getMoney(), "과일", dto.getProduct_name()); //dataset.setValue(value, rowKey, columnKey); 형식으로 들어간다. //금액, 과일, 상품이름이 들어간다. (총 3개의 값이 들어감) } //파이 차트인 경우 //DefaultPieDataset dataset = new DefaultPieDataset(); //for (CartDTO dto : list) { //dataset.setValue(dto.getProduct_name(), dto.getMoney()); //파이차트에는 x,y축이 없기 때문에 값이 2개만 들어간다. //그러니까 rowKey값이 안들어간다. //} //dataset.setValue(value, rowKey, columnKey); 형식은 이렇게 되지만, 값이 2개만 들어감 JFreeChart chart = null; //차트 객체 선언 String title = "장바구니 통계"; //장바구니 타이틀의 제목 try { // 선그래프 // chart = ChartFactory.createLineChart( // title, "상품명" , "금액" , dataset, // PlotOrientation.VERTICAL, true, true, // false); // 라인 (선) 그래프에서는 이런 값들이 들어간다. // title, categoryAxisLabel, valueAxisLabel, dataset //막대 그래프 chart = ChartFactory.createBarChart( //세로형식의 막대그래프를 만듦 title, "상품명", "금액", dataset, PlotOrientation.VERTICAL, //세로로 차트를 만든다는 의미 true, true, false); //파이 차트 //chart = ChartFactory.createPieChart( //title, //chart title //dataset, //data //true, //include legend //true, //false); //제목, 타이틀의 폰트와 글씨크기를 설정 chart.getTitle().setFont( new Font("돋움",Font.BOLD, 15)); //범례, 범례의 폰트와 글씨크기를 설정 chart.getLegend().setItemFont( new Font("돋움",Font.PLAIN, 10)); Font font = new Font("돋움", Font.PLAIN,12); Color color = new Color(0,0,0); StandardChartTheme chartTheme = (StandardChartTheme) StandardChartTheme.createJFreeTheme(); //테마 설정 chartTheme.setExtraLargeFont(font); //폰트 크기에 따라 테마를 다르게 설정 chartTheme.setLargeFont(font); chartTheme.setRegularFont(font); chartTheme.setSmallFont(font); chartTheme.setAxisLabelPaint(color); //축, 범례등의 색상을 변경 chartTheme.setLegendItemPaint(color); chartTheme.setItemLabelPaint(color); chartTheme.apply(chart); } catch (Exception e) { e.printStackTrace(); } return chart; } } | cs |
jchart02.jsp (컨트롤러에서 넘어온 메시지가 출력되는 View페이지, jcart01타입은 그 컨트롤러에서 바로 출력되기때문에 View가 필요없다.) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | .<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Insert title here</title> <%@ include file = "../include/header.jsp" %> </head> <body> <%@ include file = "../include/admin_menu.jsp" %> <h2>${message}</h2> <!-- JFreeChartController에서 리턴된 메시지가 출력된다--> <!-- pdf가 만들어 졌는지, 안만들어졌는지.. --> </body> </html> | cs |
Back-End/Spring 2019. 6. 20. 11:56
- 구글에서 제공하는 구글 차트 -
https://google-developers.appspot.com/chart/
차트그리기는 구글서버에 차트에 넣을 값만 넘겨주면 그것을 받아서 뿌려주는 형식으로 되어있다.
구글차트에서는 우리가 서버에다가 요청을 하면 제이슨으로 데이터가 넘어오게 된다.
(즉, json을 만들어서 javascript로 넣어주면 차트를 그려주는 방식)
제이슨 방식 (xml 방식보다 더 간결해서 요즘에 많이 사용)
|
xml 방식 |
{"name" : "김철수" , "email" : "kim@gmail.com", "age" : 21 }
|
<person> <name> 김철수 </name> <email> kim@gmail.com </email> <age> 21 </age> </person>
|
1. pom.xml에 라이브러리를 추가
(추가하는 이유 : 제이슨으로 넘어온 값들을 파싱
(ex-이름은 이거고, 이메일을 저거고.... 등등 따로 코딩하지 않고 자동으로 하게끔 하기 위해서) 하기 위해서)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
<!-- https://mvnrepository.com/artifact/com.googlecode.json-simple/json-simple -->
<dependency>
<groupId>com.googlecode.json-simple</groupId>
<artifactId>json-simple</artifactId>
<version>1.1.1</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.9</version>
</dependency>
|
cs |
2. 자바스크립트를 이용하여 차트 작성에 필요한 JSON 데이터를 리턴받아 화면에 출력시킴
-구글 차트 실습 예제-
admin_menu.jsp에 각 차트에 대한 하이퍼링크를 추가한다.
admin_menu.jsp 중 일부
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
.<a href="${path}/pdf/list.do">PDF</a>
ㅣ
<a href="${path}/chart/chart1.do">구글차트(json)</a>
ㅣ
<a href="${path}/chart/chart2.do">구글차트(db)</a>
ㅣ
<a href="${path}/jchart/chart2.do">JFreeChart(png)</a>
ㅣ
<a href="${path}/jchart/chart2.do">JFreeChart(pdf)</a>
ㅣ
<a href="${path}/email/write.do">이메일 발송</a>
ㅣ
<a href="${path}/shop/product/list.do">상품목록</a>
ㅣ
<a href="${path}/shop/product/write.do">상품등록</a>
ㅣ
|
cs |
구글차트 (json) : json을 사용해서 차트를 그리는 방법
구글차트 (db) : db를 읽어들여서 제이슨을 생성해서 차트를 그리는 방법
JFreeChart (png) : JFreeChart로는 그림으로 이미지 파일 차트를 추적하는 방법
JFreeChart (pdf) : 차트를 pdf로 출력하는 방법
장바구니 기능을 연동해서 쓸것이기 때문에 그 쪽은 서비스나 모델을 안만들고 사용할 예정 (장바구니 기능과 연동된 부분만)
주로 컨트롤러로 들어가고 뷰 (jsp) 쪽, 서비스 쪽을 만들 예정
컨트롤러 생성
GoogleChartController.jsp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
.package com.example.spring02.controller.chart;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView;
@RestController //json을 리턴하는 method가 있는 경우
@RequestMapping("/chart/*") //공통적인 맵핑 url
//일반적인 controller어노테이션을 jsp <=> controller을 연동할때 사용하지만
//RestController은 그 데이터 자체를 받아서 제이슨 형식으로 바꿔서 출력하고 싶을때 사용
//(지금은 json 형식으로 차트를 그릴것이기 때문에 Rest를 붙여서 컨트롤러를 선언한 것이다)
public class GoogleChartController {
@RequestMapping("chart1.do") //view에서 맵핑되는 url
public ModelAndView chart1() {
return new ModelAndView("chart/chart01");
//새로운 ModelAndView객체를 만들어서 chart/chart01페이지로 이동
}
}
|
cs |
화면이 이동하는게 아니라 화면이 멈춰져 있는 상태에서 백그라운드에서 데이터가 이동하게 할 예정
그렇기 때문에 정적인 제이슨 파일 (미리만들어진) 을 사용할 예정
json파일은 file로 만들면 된다. (따로 형식이 없음)
sampleData2.json (제이슨 파일)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
//구글에서 제공하는 구글 차트를 쓰려면 해야되는 형식
//이 제이슨 데이터를 구글서버에 보내면 서버에서 이걸 해석해서 차트를 그려서 보내준다.
{
"cols": [
{"id":"", "label":"Topping","pattern":"", "type":"string"},
{"id":"", "label":"Slices","pattern":"", "type":"number"}
],
"rows":[
{"c":[{"v":"Mushrooms"},{"v":3}]},
{"c":[{"v":"Onions"},{"v":1}]}
{"c":[{"v":"Olives"},{"v":1}]}
{"c":[{"v":"Zucchini"},{"v":1}]}
{"c":[{"v":"Pepperoni"},{"v":2}]}
]
}
|
cs |
sampleData.json (제이슨 파일)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
|
{
"rows" : [ //rows는 행이라는 뜻
{
"c" : [
{
"v" : "귤" //컬럼의 이름 (상품명)
},
{
"v" :35000 //컬럼에 해당하는 값 (가격)
}
]
},
{
"c" : [
{
"v" : "딸기"
},
{
"v" :88000
}
]
},
"c" : [
{
"v" : "오렌지"
},
{
"v" :20000
}
]
},
"c" : [
{
"v" : "키위"
},
{
"v" :30000
}
]
},
"c" : [
{
"v" : "포도"
},
{
"v" : 15000
}
]
]
},
"cols" : [ //컬럼 정보
{
"label" : "상품명", //컬럼의 이름
"type" : "string" //컬럼의 자료형
},
{
"label" : "금액",
"type" : "number"
}
]
}
|
cs |
servlet-context.xml에 리소스 매핑을 추가
|
<resources location="/WEB-INF/views/json/" mapping="/json/**" />
|
cs |
chart01.jsp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
|
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!--views/chart_exam/chart01.jsp -->
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<%@ include file="../include/header.jsp"%>
<!-- 구글 차트 호출을 위한 js 파일 -->
<script type="text/javascript" src="https://www.google.com/jsapi"></script>
<script>
//구글 차트 라이브러리 로딩
//google객체는 위쪽 google src안에 들어있음
google.load('visualization','1',{
'packages' : ['corechart']
});
//로딩이 완료되면 drawChart 함수를 호출
google.setOnLoadCallback(drawChart); //라이브러리를 불러오는 작업이 완료되었으면 drawChart작업을 실행하라는 뜻.
function drawChart() {
var jsonData = $.ajax({ //비동기적 방식으로 호출한다는 의미이다.
url : "${path}/json/sampleData.json",
//json에 sampleData.json파일을 불러온다.
//확장자가 json이면 url 맵핑을 꼭 해주어야 한다. 안해주면 자바파일인줄 알고 404에러가 발생한다.
//그렇기 때문에 servlet-context파일에서 리소스를 맵핑해준다.
dataType : "json",
async : false
}).responseText; //제이슨파일을 text파일로 읽어들인다는 뜻
console.log(jsonData);
//데이터테이블 생성
var data
= new google.visualization.DataTable(jsonData);
//제이슨 형식을 구글의 테이블 형식으로 바꿔주기 위해서 집어넣음
//차트를 출력할 div
//LineChart, ColumnChart, PieChart에 따라서 차트의 형식이 바뀐다.
var chart = new google.visualization.PieChart(
document.getElementByld('chart_div')); //원형 그래프
//var chart
// = new google.visualization.LineChart(
//document.getElementById('chart_div')); 선 그래프
//var chart
// = new google.visualization.ColumnChart(document.getElementById('chart_div'));
//차트 객체.draw(데이터 테이블, 옵션) //막대그래프
//cuveType : "function" => 곡선처리
//데이터를 가지고 (타이틀, 높이, 너비) 차트를 그린다.
chart.draw(data, {
title : "차트 예제",
//curveType : "function", //curveType는 차트의 모양이 곡선으로 바뀐다는 뜻
width : 600,
height : 400
});
}
</script>
</head>
<body>
<%@ include file="../include/admin_menu.jsp"%>>
<!-- 차트 출력 영역 -->
<div id="chart_div"></div>
<!-- 차트가 그려지는 영역 -->
<!-- 차트 새로고침 버튼 -->
<button id="btn" type="button" onclick="drawChart()">refresh</button>
</body>
</html>
|
cs |
======여기까지는 정적인 json (그러니까 json의 주소로 직접이동해서 사용하는 방식=================================
json을 만드는 방법 (실습)
데이터베이스를 읽어서 구글에서 요구하는 json 형식으로 데이터를 만들면 된다.
GoogleChartService.java
|
package com.example.spring02.service.chart;
import org.json.simple.JSONObject;
//json오브젝트는 pom.xml에 추가한 라이브러리 안에 들어있는 것들이다
public interface GoogleChartService {
public JSONObject getChartData(); //json 타입으로 리턴
}
|
cs |
GoogleChartServiceImpl.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
|
package com.example.spring02.service.chart;
import javax.inject.Inject;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.springframework.stereotype.Service;
import com.example.spring02.model.shop.dto.CartDTO;
import com.example.spring02.service.shop.CartService;
import com.itextpdf.text.List;
@Service
public class GoogleCharServiceImpl
implements GoogleChartService {
@Inject
CartService cartService;
//장바구니 서비스에 있는 값들을 가져오기 위해서 의존성을 주입
//{"변수명" : [{},{},{}], "변수명" : "값"}
@Override
public JSONObject getChartData() {//제이슨 오브젝트를 리턴하는 것
// getChartData메소드를 호출하면
//db에서 리스트 받아오고, 받아온걸로 json형식으로 만들어서 리턴을 해주게 된다.
List<CartDTO> items = cartService.cartMoney();
//리턴할 json 객체
JSONObject data = new JSONObject(); //{}
//json의 칼럼 객체
JSONObject col1 = new JSONObject();
JSONObject col2 = new JSONObject();
//json 배열 객체, 배열에 저장할때는 JSONArray()를 사용
JSONArray title = new JSONArray();
col1.put("label","상품명"); //col1에 자료를 저장 ("필드이름","자료형")
col1.put("type", "string");
col2.put("label", "금액");
col2.put("type", "number");
//테이블행에 컬럼 추가
title.add(col1);
title.add(col2);
//json 객체에 타이틀행 추가
data.put("cols", title);//제이슨을 넘김
//이런형식으로 추가가된다. {"cols" : [{"label" : "상품명","type":"string"}
//,{"label" : "금액", "type" : "number"}]}
JSONArray body = new JSONArray(); //json 배열을 사용하기 위해 객체를 생성
for (CartDTO dto : items) { //items에 저장된 값을 dto로 반복문을 돌려서 하나씩 저장한다.
JSONObject name = new JSONObject(); //json오브젝트 객체를 생성
name.put("v", dto.getProduct_name()); //name변수에 dto에 저장된 상품의 이름을 v라고 저장한다.
JSONObject money = new JSONObject(); //json오브젝트 객체를 생성
money.put("v", dto.getMoney()); //name변수에 dto에 저장된 금액을 v라고 저장한다.
JSONArray row = new JSONArray(); //json 배열 객체 생성 (위에서 저장한 변수를 칼럼에 저장하기위해)
row.add(name); //name을 row에 저장 (테이블의 행)
row.add(money); //name을 row에 저장 (테이블의 행)
JSONObject cell = new JSONObject();
cell.put("c", row); //cell 2개를 합쳐서 "c"라는 이름으로 추가
body.add(cell); //레코드 1개 추가
}
data.put("rows", body); //data에 body를 저장하고 이름을 rows라고 한다.
return data; //이 데이터가 넘어가면 json형식으로 넘어가게되서 json이 만들어지게 된다.
}
}
|
cs |
CartDAOImpl.java
|
@Override
public List<CartDTO> cartMoney() {
return sqlSession.selectList("cart.cart_money");
}
|
cs |
cartMapper.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
<mapper namespace="cart">
<select id = "cart_money"
resultType = "com.example.spring02.model.shop.dto.CartDTO">
select product_name, sum(price * amount) money
from cart c, product p
where c.product_id=p.product_id
group by product_name
order by product_name
<!-- 상품테이블과 장바구니 테이블로부터 상품의 이름과 전체 금액을 검색 -->
<!-- 조건 : 장바구니 테이블의 상품 id와 상품 테이블의 상품 id가 같은 것만 (즉, 내가 장바구니에 담은 상품의 id만) -->
<!-- 그리고 검색한 것들을 product_name란 속성을 만들어서 내림차순으로 정렬시킴 -->
</select>
|
cs |
===========================================여기까지 json파일 생성 과정=============================
아까는 json의 주소를 직접 적었지만
이제는 컨트롤러에 가서 json을 동적으로 생성하게 만들어서 그것을 보내주고 있는것.
GoogleCharController.java
컨트롤러를 선언할때 controller 어노테이션을 사용하면 ResponseBody어노테이션을 붙여야 하고,
컨틀롤러를 선언할때 RestController 어노테이션을 붙이면 ResponseBody어노테이션을 안붙여도 된다.
|
@RequestMapping("chart2.do")
public ModelAndView chart2() {
return new ModelAndView("chart/chart02"); //json데이터를 호출한 곳으로 되돌려준다.
}
//@ResponseBody //화면으로 넘어가는 것이 아닌 데이터를 리턴하는 경우 사용
@RequestMapping("cart_money_list.do")
public JSONObject cart_money_list() {
return GoogleChartService.getChartData();
}
|
cs |
chart02.jsp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
|
.<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!--views/chart_exam/chart02.jsp -->
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
<%@ include file="../include/header.jsp"%>
<!-- 구글 차트 호출을 위한 js 파일 -->
<script type="text/javascript" src="https://www.google.com/jsapi"></script>
<script>
//구글 차트 라이브러리 로딩
//google객체는 위쪽 google src안에 들어있음
google.load('visualization','1',{
'packages' : ['corechart']
});
//로딩이 완료되면 drawChart 함수를 호출
google.setOnLoadCallback(drawChart); //라이브러리를 불러오는 작업이 완료되었으면 drawChart작업을 실행하라는 뜻.
function drawChart() {
var jsonData = $.ajax({ //비동기적 방식으로 호출한다는 의미이다.
url : "${path}/chart/cart_money_list.do",
//chart01에서는 json의 주소를 직접 적었지만 이 페이지에서는 컨트롤러로 이동해 맵핑해서 제이슨을 동적으로
//직접만들어 그 만든 json을 직접 보낸다.
//chart01에서 쓰던 방식 url : "${path}/json/sampleData.json",
//json에 sampleData.json파일을 불러온다.
//확장자가 json이면 url 맵핑을 꼭 해주어야 한다. 안해주면 자바파일인줄 알고 404에러가 발생한다.
//그렇기 때문에 servlet-context파일에서 리소스를 맵핑해준다.
dataType : "json",
async : false
}).responseText; //제이슨파일을 text파일로 읽어들인다는 뜻
console.log(jsonData);
//데이터테이블 생성
var data
= new google.visualization.DataTable(jsonData);
//제이슨 형식을 구글의 테이블 형식으로 바꿔주기 위해서 집어넣음
//차트를 출력할 div
//LineChart, ColumnChart, PieChart에 따라서 차트의 형식이 바뀐다.
//var chart = new google.visualization.PieChart(
//document.getElementByld('chart_div')); //원형 그래프
var chart
= new google.visualization.LineChart(
document.getElementById('chart_div')); //선 그래프
//var chart
// = new google.visualization.ColumnChart(document.getElementById('chart_div'));
//차트 객체.draw(데이터 테이블, 옵션) //막대그래프
//cuveType : "function" => 곡선처리
//데이터를 가지고 (타이틀, 높이, 너비) 차트를 그린다.
chart.draw(data, {
title : "장바구니 통계",
curveType : "function", //curveType는 차트의 모양이 곡선으로 바뀐다는 뜻
width : 600,
height : 400
});
}
</script>
</head>
<body>
<%@ include file="../include/admin_menu.jsp"%>>
<!-- 차트 출력 영역 -->
<div id="chart_div"></div>
<!-- 차트가 그려지는 영역 -->
<!-- 차트 새로고침 버튼 -->
<button id="btn" type="button" onclick="drawChart()">refresh</button>
</body>
</html>
|
cs |
아래 책은 제가 공부할때 활용했던 책으로 추천드리는 책이니 한번씩 읽어보시는것을 추천드립니다!! ㅎㅎ

이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.
Back-End/Spring 2019. 6. 19. 23:21
스프링을 사용해서 pdf파일 생성해보기
- itextpdf 라이브러리 -
- 참고할만한 사이트들 -
- http://itextpdf.com (pdf관련 예제 수록)
- API : http://developers.itextpdf.com/examples-itext5 (pdf관련 API)
|
사전 설정
pom.xml에 pdf에 한글처리를 위해 폰트 정보를 메이븐 저장소 홈페이지에서 복사해온다.
기본 구조
뷰 => 컨트롤러 => Service => dto => Service => 컨트롤러 => 뷰
1. admin_menu.jsp 에서 pdf링크를 만들어 list.do ( url )로 컨트롤러와 맵핑
2. pdf파일을 만들기 위해 컨트롤러에서 서비스, 서비스에서 서비스 구현 클래스를 호출
3. PdfServiceImpl.java에서 pdf를 만들기 위해 createpdf메소드를 실행
ㄱ. pdf 문서를 처리하는 객체인 Document 생성
ㄴ. pdf 문서의 저장경로 설정, 한글폰트 처리 및 폰트의 사이즈를 따로 지정 해준다.
ㄷ. pdf 문서에 나타날 셀을 설정하고 테이블에 집어넣는다.
ㄹ. 타이틀을 지정하고, 가운데 정렬하고, 줄바꿈을 해준다. (타이틀이 테이블보다 위쪽에 있기 때문에)
ㅁ. 위에서 만든 셀에 "상품명", "수량", "단가", "금액" 값을 정렬방식과 폰트를 지정해서 넣는다.
ㅂ. 그리고 테이블에 위에서 생성시킨 셀을 넣는다.
ㅅ. 서비스에 저장되어있던 장바구니리스트에 id값을 매개값으로 리스트에 저장
ㅇ. 리스트에 저장한 값들을 반복문을 사용해서 하나씩 출력해서 dto에 저장한다. ㄱ. pdf 문서를 처리하는 객체인 Document 생성
ㄴ. pdf 문서의 저장경로 설정, 한글폰트 처리 및 폰트의 사이즈를 따로 지정 해준다.
ㄷ. pdf 문서에 나타날 셀을 설정하고 테이블에 집어넣는다.
ㄹ. 타이틀을 지정하고, 가운데 정렬하고, 줄바꿈을 해준다. (타이틀이 테이블보다 위쪽에 있기 때문에)
ㅁ. 위에서 만든 셀에 "상품명", "수량", "단가", "금액" 값을 정렬방식과 폰트를 지정해서 넣는다.
ㅂ. 그리고 테이블에 위에서 생성시킨 셀을 넣는다.
ㅅ. 서비스에 저장되어있던 장바구니리스트에 id값을 매개값으로 리스트에 저장
ㅇ. 리스트에 저장한 값들을 반복문을 사용해서 하나씩 출력해서 dto에 저장한 ㅈ. dto에 저장한 값들을 pdfCell 객체를 생성해서 cell안에 넣어준다.
ㅊ. Cell에 저장한 데이터들을 table 안에 저장한다. ㅋ. document 객체에 table를 저장하고, 저장이 끝났으면 document객체를 닫는다.
4. createpdf 메소드를 실행한 후 컨트롤러로 돌아옴
5. 컨트롤러에서 결과값을 result.jsp에 전달해서 pdf파일이 생성되었는지, 안되었는지 확인하고 결과에 대한 메시지가 result.jsp 파일에 출력이 되도록 한다.
|
1. 한글 처리를 위해서는 폰트 정보가 필요함
pom.xml에 라이브러리를 추가. (메이븐 저장소홈페이지에서 복사해온다.) (https://mvnrepository.com/search?q=itextpdf&p=1) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | <!-- https://mvnrepository.com/artifact/com.itextpdf/itextpdf --> <dependency> <groupId>com.itextpdf</groupId> <artifactId>itextpdf</artifactId> <version>5.5.13</version> </dependency> <!-- https://mvnrepository.com/artifact/com.itextpdf/itext-pdfa --> <dependency> <groupId>com.itextpdf</groupId> <artifactId>itext-pdfa</artifactId> <version>5.5.13</version> <scope>test</scope> </dependency> <!-- https://mvnrepository.com/artifact/com.itextpdf/itext-xtra --> <dependency> <groupId>com.itextpdf</groupId> <artifactId>itext-xtra</artifactId> <version>5.5.13</version> </dependency> <!-- https://mvnrepository.com/artifact/com.itextpdf.tool/xmlworker --> <dependency> <groupId>com.itextpdf.tool</groupId> <artifactId>xmlworker</artifactId> <version>5.5.13</version> </dependency> <!-- https://mvnrepository.com/artifact/com.itextpdf/font-asian --> <dependency> <groupId>com.itextpdf</groupId> <artifactId>font-asian</artifactId> <version>7.1.6</version> <scope>test</scope> </dependency> | cs |
2. pdf 기능을 테스트하기 위해서 관리자 메뉴 페이지에 pdf 링크 추가
admin_menu.jsp 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> <!-- core태그를 사용하기 위해 taglib를 사용 --> <!-- 관리자로그인한 상태에서만 보이는 메뉴 --> <!-- 메뉴 링크를 추가하고 PDF리스트로 갈수있는 링크도 추가 --> <a href="${path}/shop/product/list.do">상품목록</a> ㅣ <a href="${path}/shop/product/write.do">상품등록</a> ㅣ <a href="${path}/pdf/list.do">PDF</a> ㅣ <c:choose> <c:when test="${sessionScope.admin_userid == null }"> <a href="${path }/admin/login.do">관리자 로그인</a> <!-- 세션에 관리자 아이디의 값이 NULL일때 (즉 로그인 되어있지 않은 상태일때) --> <!-- 관리자 로그인 링크를 표시 --> </c:when> <c:otherwise> ${sessionScope.admin_name}님이 로그인중입니다. <a href="${path}/admin/logout.do">로그아웃</a> <!-- 관리자가 로그인한 상태일때는 로그아웃 링크를 표시 --> </c:otherwise> </c:choose> <hr> | cs |
3. PdfController.java 로 맵핑된다. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | package com.example.spring02.controller.pdf; import javax.inject.Inject; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.servlet.ModelAndView; import com.example.spring02.service.pdf.PdfService; @Controller //컨트롤러 표시 어노테이션 @RequestMapping("/pdf/*")//공통주소를 맵핑 public class PdfController { @Inject PdfService pdfService; //서비스 객체를 사용하기 위해 의존성을 주입 @RequestMapping("list.do") //View에서 맵핑 url 주소 public ModelAndView list() throws Exception { String result = pdfService.createPdf(); //createPdf()메소드에서 pdf파일이 생성되었는지 결과가 result에 담긴다. return new ModelAndView("pdf/result","message",result); //그 결과가 message로 pdf/result페이지로 전송된다. } } | cs |
PdfService.java | package com.example.spring02.service.pdf; public interface PdfService { public String createPdf(); //pdf를 만드는 추상 메소드 } | cs |
PdfServiceImpl.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 | package com.example.spring02.service.pdf; import java.io.FileOutputStream; import javax.inject.Inject; import org.springframework.stereotype.Service; import com.example.spring02.model.shop.dto.CartDTO; import com.example.spring02.service.shop.CartService; import com.itextpdf.text.Chunk; import com.itextpdf.text.Document; import com.itextpdf.text.Element; import com.itextpdf.text.Font; import com.itextpdf.text.List; import com.itextpdf.text.Paragraph; import com.itextpdf.text.Phrase; import com.itextpdf.text.pdf.BaseFont; import com.itextpdf.text.pdf.PdfPCell; import com.itextpdf.text.pdf.PdfPTable; import com.itextpdf.text.pdf.PdfWriter; @Service //서비스에서는 이 어노테이션을 사용해야한다. public class PdfServiceImpl implements PdfService { @Inject CartService cartService; // 장바구니에 있는 내용들을 pdf파일로 만들기 위해 장바구니 서비스객체를 사용하기 위해서 의존성을 주입시킨다. @Override public String createPdf() { String result = ""; // 초기값이 null이 들어가면 오류가 발생될수 있기 때문에 공백을 지정 try { Document document = new Document(); // pdf문서를 처리하는 객체 PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream("d:/sample.pdf")); // pdf파일의 저장경로를 d드라이브의 sample.pdf로 한다는 뜻 document.open(); // 웹페이지에 접근하는 객체를 연다 BaseFont baseFont = BaseFont.createFont("c:/windows/fonts/malgun.ttf", BaseFont.IDENTITY_H, BaseFont.EMBEDDED); // pdf가 기본적으로 한글처리가 안되기 때문에 한글폰트 처리를 따로 해주어야 한다. // createFont메소드에 사용할 폰트의 경로 (malgun.ttf)파일의 경로를 지정해준다. // 만약에 이 경로에 없을 경우엔 java파일로 만들어서 집어넣어야 한다. Font font = new Font(baseFont, 12); // 폰트의 사이즈를 12픽셀로 한다. PdfPTable table = new PdfPTable(4); // 4개의 셀을 가진 테이블 객체를 생성 (pdf파일에 나타날 테이블) Chunk chunk = new Chunk("장바구니", font); // 타이틀 객체를 생성 (타이틀의 이름을 장바구니로 하고 위에 있는 font를 사용) Paragraph ph = new Paragraph(chunk); ph.setAlignment(Element.ALIGN_CENTER); document.add(ph); // 문단을 만들어서 가운데 정렬 (타이틀의 이름을 가운데 정렬한다는 뜻) document.add(Chunk.NEWLINE); document.add(Chunk.NEWLINE); // 줄바꿈 (왜냐하면 타이틀에서 두줄을 내린후에 셀(테이블)이 나오기 때문) PdfPCell cell1 = new PdfPCell(new Phrase("상품명", font)); // 셀의 이름과 폰트를 지정해서 셀을 생성한다. cell1.setHorizontalAlignment(Element.ALIGN_CENTER); // 셀의 정렬방식을 지정한다. (가운데정렬) PdfPCell cell2 = new PdfPCell(new Phrase("단가", font)); cell2.setHorizontalAlignment(Element.ALIGN_CENTER); PdfPCell cell3 = new PdfPCell(new Phrase("수량", font)); cell3.setHorizontalAlignment(Element.ALIGN_CENTER); PdfPCell cell4 = new PdfPCell(new Phrase("금액", font)); cell4.setHorizontalAlignment(Element.ALIGN_CENTER); table.addCell(cell1); // 그리고 테이블에 위에서 생성시킨 셀을 넣는다. table.addCell(cell2); table.addCell(cell3); table.addCell(cell4); List<CartDTO> items = cartService.listCart("park"); // 서비스로부터 id값을 매개값으로 주어서 장바구니목록을 가져온다. for (int i = 0; i < items.size(); i++) { CartDTO dto = items.get(i); // 레코드에 값들을 꺼내서 dto에 저장 PdfPCell cellProductName = new PdfPCell(new Phrase(dto.getProduct_name(), font)); // 반복문을 사용해서 상품정보를 하나씩 // 출력해서 셀에 넣고 테이블에 // 저장한다. PdfPCell cellPrice = new PdfPCell(new Phrase("" + dto.getPrice(), font)); // Phrase타입은 숫자형(int형 같은타입)으로 하면 에러가 발생되기 때문에 dto앞에 공백("")주어서 String타입으로 변경한다. PdfPCell cellAmount = new PdfPCell(new Phrase("" + dto.getAmount(), font)); // Phrase타입은 숫자형(int형 같은타입)으로 하면 에러가 발생되기 때문에 dto앞에 공백("")주어서 String타입으로 변경한다. PdfPCell cellMoney = new PdfPCell(new Phrase("" + dto.getMoney(), font)); // Phrase타입은 숫자형(int형 같은타입)으로 하면 에러가 발생되기 때문에 dto앞에 공백("")주어서 String타입으로 변경한다. table.addCell(cellProductName); // 셀의 데이터를 테이블에 저장한다. (장바구니안에 들어있는 갯수만큼 테이블이 만들어진다) table.addCell(cellPrice); table.addCell(cellAmount); table.addCell(cellMoney); } document.add(table); // 웹접근 객체에 table를 저장한다. document.close(); // 저장이 끝났으면 document객체를 닫는다. result = "pdf 파일이 생성되었습니다."; } catch (Exception e) { e.printStackTrace(); result = "pdf 파일 생성 실패..."; } return result; } } | cs |
result.jsp | <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <!-- 컨트롤러에서 pdf파일이 생성되었는지 알려주는 페이지 (메시지로 알려준다) --> <title>Insert title here</title> <%@ include file = "../include/header.jsp" %> </head> <body> <%@ include file = "../include/admin_menu.jsp" %> <h2>${message}</h2> </body> </html> | cs |
Back-End/Spring 2019. 6. 18. 18:18
- 관리자용 상품등록 / 수정 / 삭제 기능 구현 - (관리자로 로그인한 상태에서만 가능)
-상품등록-
admin_menu.jsp | <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <!-- jstl을 사용하기 위한 c태그 --> <a href="${path}/shop/product/list.do">상품목록</a> | <!-- 상품목록에 들어가는 링크를 만듦 --> <a href="${path}/shop/product/write.do">상품등록</a> | <!-- 상품등록에 들어가는 링크를 만듦 -->
<c:choose> <c:when test="${sessionScope.admin_userid == null }"> <a href="${path}/admin/login.do">관리자 로그인</a> <!-- 세션에 들어있는 관리자 id가 null값이면 로그인 페이지로 이동함 --> </c:when>
<c:otherwise> ${sessionScope.admin_name}님이 로그인중입니다. <a href="${path}/admin/logout.do">로그아웃</a> <!-- 로그인 중이면 로그아웃 페이지를 출력함) --> </c:otherwise>
</c:choose> <hr> | cs |
product_write.jsp (상품 등록) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 | <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Insert title here</title> <%@ include file="../include/header.jsp"%> <script> //상품을 추가하기위한 정보를 담아 insert.do로 보내는 자바스크립트 함수 function product_write() { var product_name = document.form1.product_name.value; // document는 웹페이지에 접근하기위한 객체.. form1에 있는 상품이름을 반환해서 name에 저장함 var price = document.form1.price.value; // document는 웹페이지에 접근하기위한 객체.. form1에 있는 상품의 값을 반환해서 price에 저장함 var description = document.form1.description.value; // document는 웹페이지에 접근하기위한 객체.. form1에 있는 상품의 정보를 반환해서 description에 저장함 //document.form.은 폼페이지에 있는 값을 반환한다는 뜻. if (product_name == "") { //상품 이름이 입력되어 있지 않으면 alert("상품명을 입력하세요"); document.form1.product_name.focus(); //form1페이지에 있는 "상품명을 입력하세요" 에 커서를 올려둔다. return; } if (price == "") { //상품가격이 입력되어 있지 않으면 alert("가격을 입력하세요"); document.form1.price.focus(); //form1페이지에 있는 "가격을 입력하세요" 에 커서를 올려둔다. return; } if (description == "") { //상품설명이 입력되어 있지 않으면 alert("상품설명을 입력하세요"); document.form1.description.focus(); //form1페이지에 있는 "상품설명을 입력하세요" 에 커서를 올려둔다. return; } // input 태그를 마우스로 클릭하여 입력상태로 만든것을 포커스를 얻었다고 한다. // 그리고 입력상태를 떠난 것을 포커스가 벗어났다고 한다.
document.form1.action = "${path}/shop/product/insert.do"; //insert.do 페이지로 form1에 저장된 자료를 전송함 document.form1.submit(); } </script> </head> <body> <%@ include file="../include/admin_menu.jsp"%> <!-- 관리자용 메뉴는 일반 회원의 메뉴와 다르기 때문에 일부러 관리자용 메뉴를 만들고 그 메뉴를 출력한다. --> <h2>상품 등록</h2> <form id="form1" name="form1" method="post" enctype="multipart/form-data"> <!-- 파일업로드를 위해 추가하는 타입 --> <table> <tr> <td>상품명</td> <td><input name="product_name"></td> </tr> <tr> <td>가격</td> <td><input name="price"></td> </tr> <tr> <td>상품설명</td> <td><textarea rows="5" cols="60" name="description" id="description"></textarea></td> </tr> <tr> <td>상품이미지</td> <td><input type="file" name="file1"></td> </tr> <tr> <td colspan="2" align="center"><input type="button" value="등록" onclick="product_write()"> <!-- "등록" 버튼을 누르면 위쪽에 있는 스크립트문에서 product_write()함수가 호출되서 실행되 insert.do페이지로 자료를 전송한다. --> <input type="button" value="목록" onclick="location.href='${path}/admin/product/list.do'"> <!-- "목록 버튼을 누르면 list.do페이지로 이동" --> </td> </tr> </table> </form> </body> </html> | cs |
ProductController.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | //상품을 추가하는 메소드 @RequestMapping("write.do") public String write() { return "shop/product_write"; }
==================================================================================================================== //관리자 페이지에서 맵핑된 메소드 //첨부파일을 추가하는 메소드 (그러니까 과일의 사진을 추가) @RequestMapping("insert.do") public String insert(ProductDTO dto) { String filename="-"; if(!dto.getFile1().isEmpty()) { //첨부파일이 존재하면 (isEmpty()는 빈공간이라는 뜻인데 !가 붙었으므로 첨부파일이 존재하면..이라는 뜻) filename=dto.getFile1().getOriginalFilename(); //dto에 저장된 서버상에 업로드된 파일명을 반환해서 filename변수에 저장한다. String path="D:\\work\\.metadata\\.plugins\\org.eclipse.wst.server.core\\tmp1\\wtpwebapps\\spring02\\WEB-INF\\views\\images\\"; //이미지 파일이 저장된 경로를 지정 //개발디렉토리가 아니라 곧바로 배포디렉토리로 설정하였다.
//개발디렉토리에서 앞부분을 자르고(d:\work\spring02 까지), 그 부분에 배포디렉토리를 붙여넣으면 된다. //이렇게 하지 않으면 이미지를 추가했을때 개발 디렉토리와 배포 디렉토리가 다르기 때문에 일일히 새로고침을 해주어야 한다. 이클립스에서는 개발을 할때는 워크스페이스 (개발디렉토리) 에서 개발한 코드를 톰캣에서 카피해서 배포 디렉토리에 배포를 한다. (카피를 할때 새로고침을 해야한다)
개발 디렉토리
d:\work\spring02
배포 디렉토리
D:\work\.metadata\.plugins\org.eclipse.wst.server.core\tmp1\wtpwebappsdd\spring02\ //파일업로드시에는 예외처리를 해주어야 한다. try { new File(path).mkdir(); //새로운 파일의 경로를 생성하고 해당 경로에 폴더를 만든다. dto.getFile1().transferTo(new File(path+filename)); //생성한 디렉터리에 파일을 저장한다. (dto에 저장한다는 뜻) } catch (Exception e) { e.printStackTrace(); } } dto.setPicture_url(filename); //첨부파일을 dto에 저장 productService.insertProduct(dto); //서비스에 dto에 있는 과일 이미지 사진을 저장함 return "redirect:/shop/product/list.do"; //파일이 첨부되면 list페이지로 되돌아간다. }
| cs |
ProductServiceImpl.java 중 일부 | @Override public void insertProduct(ProductDTO dto) { productDao.insertProduct(dto); } | cs |
ProductDAOImpl.java 중 일부 | @Override public void insertProduct(ProductDTO dto) { sqlSession.insert("product.insert", dto); } | cs |
productMapper.java 중 일부 | <insert id="insert"> insert into product values (seq_product.nextval, #{product_name}, #{price}, #{description}, #{picture_url} ) //seq_product.nextval은 상품코드를 시퀀스를 이용해서 발급하는 것. //그러니까 숫자가 하나씩 올라간다는 뜻. </insert> | cs |
-상품수정-
상품 수정을 할때는 url에 상품id(숫자)를 넘겨서 @PathVariable로 받을 예정
product_list.jsp 중 일부 (편집버튼 추가) | <c:if test = "${sessionScope.admin_userid != null}"> <br> <a href="${path }/shop/product/edit/${row.product_id}">[편집]</a> </c:if> | cs |
ProductController.java | //상품정보 편집 페이지로 이동하고 데이터를 보내주도록하는 메소드 //상품의 아이디를 맵핑해서.. @RequestMapping("edit/{product_id}") public ModelAndView edit(@PathVariable("product_id") int product_id, ModelAndView mav) { //다른페이지에서 pathvariable로 받은 product_id를 product_id에 저장하고, //데이터를 보내고, 페이지를 이동하기위해서 ModelAndView 타입을 사용한다. mav.setViewName("/shop/product_edit"); //이동할 페이지의 이름 //전달할 데이터를 저장 mav.addObject("dto", productService.detailProduct(product_id)); //서비스로부터 상품 id(번호)를 받아와서 mav에 저장 return mav; //페이지 이동 } | cs |
ProductService.java 중 일부 | @Override public ProductDTO detailProduct(int product_id) { return productDao.detailProduct(product_id); // } | cs |
ProductDAOImpl.java 중 일부 | @Override public ProductDTO detailProduct(int product_id) { return sqlSession.selectOne( "product.detail_product", product_id); } | cs |
product_edit.jsp 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Insert title here</title> <%@ include file="../include/header.jsp"%> <script> //상품을 갱신하는 함수 //컨트롤러의 update.do로 맵핑된다. function product_update() { document.form1.action = "${path}/shop/product/update.do"; document.form1.submit(); } //상품을 삭제하는 함수 //컨트롤러의 delete.do로 맵핑된다. function product_delete() { if (confirm("삭제하시겠습니까?")) { document.form1.action = "${path}/shop/product/delete.do"; document.form1.submit(); } } </script> </head> <body> <%@ include file="../include/admin_menu.jsp"%> <h2>상품 정보 편집</h2> <form id="form1" name="form1" method="post" enctype="multipart/form-data"> <!-- 파일 업로드를 하기위한 타입, 필수로 작성해야 한다.--> <table> <!-- 관리자로그인을 한 후에 들어갈 수 있는 상품정보 편집정보 --> <!-- 해당되는 자료들은 dto에서 가져와서 보여준다. --> <tr> <td>상품명</td> <td><input name="product_name" value="${dto.product_name}"></td> </tr> <tr> <td>가격</td> <td><input name="price" type="number" value="${dto.price }"></td> </tr> <tr> <td>상품설명</td> <td><textarea rows="5" cols="60" name="description" id="description">${dto.description }</textarea></td> </tr> </table> </form> </body> </html> | cs |
ProductController.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
//상품의 정보를 수정 (갱신) 할때 View에서 맵핑되는 메소드 @RequestMapping("update.do") public String update(ProductDTO dto) { String filename = "-"; if(!dto.getFile1().isEmpty()) { //첨부파일이 존재하면 filename = dto.getFile1().getOriginalFilename();//dto에 저장된 서버상에 업로드된 파일명을 반환해서 filename변수에 저장한다. String path="D:\\work\\.metadata\\.plugins\\org.eclipse.wst.server.core\\tmp1\\wtpwebapps\\spring02\\WEB-INF\\views\\images\\"; //이미지 파일이 저장된 경로를 지정 try { new File(path).mkdir(); //새로운 파일의 경로를 생성하고 해당 경로에 폴더를 만든다. dto.getFile1().transferTo(new File(path+filename)); //지정된 디렉토리로 카피하는 명령어 } catch (Exception e) { //생성한 디렉터리에 파일을 저장한다. (dto에 저장한다는 뜻) e.printStackTrace(); } dto.setPicture_url(filename); //이미지의 경로 }else { //새로운 첨부파일이 올라가지않고 기존에 있는 정보를 그대로 써야하는 경우 //기존의 정보를 가져와서 dto2변수에 넣고, dto ProductDTO dto2= productService.detailProduct(dto.getProduct_id()); dto.setPicture_url(dto2.getPicture_url()); } productService.updateProduct(dto); return "redirect:/shop/product/list.do"; } | cs |
ProductServiceImpl.java 중 일부 | @Override public void updateProduct(ProductDTO dto) { productDao.updateProduct(dto); } | cs |
ProductDAO.Impl.java 중 일부 | @Override public void updateProduct(ProductDTO dto) { sqlSession.update("Product.update_product",dto); } | cs |
productMapper.xml 중 일부 | <mapper namespace="product"> <update id = "update_product"> update product set product_name = #{product_name}, price=#{price}, description=#{description}, picture_url=#{picture_url} where product_id=#{product_id} <!-- 상품 id와 맞는 상품의 가격, 설명, 사진을 갱신하는 쿼리문 --> </update> | cs |
-상품삭제-
상품을 삭제할때는 안에 상품안에 저장되어 있는 이미지파일도 같이 삭제하여야함.
product_edit.jsp에서 컨트롤러로 맵핑됨
ProductController.java 중 일부 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | //상품 정보를 삭제할때 뷰 (product_edit.jsp)페이지와 매핑되는 메소드 //상품 정보를 삭제할때는 그 정보 안에 담긴 이미지도 같이 삭제 해야 한다. @RequestMapping("delete.do") public String delete(@RequestParam int product_id) { //RequestParam 어노테이션을 사용해서 상품의 id를 받아온다. String filename=productService.fileInfo(product_id); //fileaname변수에 파일을 삭제하기위해 서비스에서 상품의 id를 매개변수로 삼아 서비스에 저장한후 filename 변수에 저장 if(filename != null && !filename.equals("-")) { //filename이 null값이 아니거나, filename안에 들어있는것이 아닌 것이 "-"와 같으면, (그러니까 filename에 값이 담겨있을 경우!!!!!) String path="D:\\work\\.metadata\\.plugins\\org.eclipse.wst.server.core\\tmp1\\wtpwebapps\\spring02\\WEB-INF\\views\\images\\"; //상품에 담겨있는 이미지도 같이 삭제해야하기 때문에 이미지 경로를 지정 File f = new File(path+filename); //이미지 파일을 삭제하기 위해 (파일의 객체 (경로와 파일이 담겨있음)을 생성하고 변수 f에 저장) if(f.exists()) { //exists()메소드는 유효성을 검사하는 메소드, 그러니까 값이 존재하는지 안하는지 판단하는 메소드이다. //f안에 이미지 파일과 경로가 존재한다면, delete()메소드로 변수 f안에 있는 이미지파일과 경로를 제거 (즉 파일을 제거) f.delete(); } } productService.deleteProduct(product_id); //이미지를 삭제한 후에 나머지 (가격 등등) 자료들도 삭제하기 위해 서비스에 id를 매개변수로 줘서 저장(삭제함) return "redirect:/shop/product/list.do"; //최신화 한 후에 list.jsp로 redirect한다. } | cs |
먼저 저장되어 있는 이미지를 삭제하기 위해서 서비스 => DAO => Mapper을 거쳐서 다시 컨트롤러로 이동하고 저장된 이미지를 filename변수에 저장
ProductServiceImpl.java 중 일부 | @Override public String fileInfo(int product_id) { return productDao.fileInfo(product_id); } | cs |
ProductDAOImpl.java 중 일부 | @Override public String fileInfo(int product_id) { return sqlSession.selectOne("product.file_info",product_id); } | cs |
productMapper.xml 중 일부 | <mapper namespace="product"> <select id = "file_info" resultType="String"> select picture_url from product where product_id=#{product_id} <!-- product테이블안에 있는 입력된 id에 해당하는 이미지를 검색하는 쿼리문 --> </select> </mapper> | cs |
============== 이미지를 삭제한 후에 나머지 자료들을 삭제하기 위해 서비스를 호출해서 매개값(id)를 줘서 자료를 삭제 ===========
ProductServiceImpl.java 중 일부 | @Override public void deleteProduct(int product_id) { productDao.deleteProduct(product_id); } | cs |
ProductDAOImpl.java 중 일부 | @Override public void deleteProduct(int product_id) { sqlSession.delete("product.product_delete",product_id); } | cs |
productMapper.xml 중 일부 | <mapper namespace="product"> <delete id = "product_delete"> delete from product where product_id=#{product_id} <!-- product테이블안에 있는 상품번호가 ?인 객체를 삭제하는 쿼리문 --> </delete> | cs |
Back-End/Spring 2019. 6. 17. 18:07
파일업로드
스프링 프레임워크의 내장객체
SPRING / 파일업로드 적용방법
- pom.xml 설정 -
maven build를 위해서 pom.xml 파일에 commons-fileupload.jar 과 commons-io.jar 파일을 추가 <!-- MultipartHttpServletRequset -->
<dependencies>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.0.1</version>
</dependency>
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.2.2</version>
</dependency>
</dependencies>
- spring-context.xml 설정 (spring bean 설정) -
1. CommonsMultipartResolver 는 스프링 프레임 워크에 내장되어 있음
2. property -> maxUploadSize : 파일 업로드 시 최대로 올릴 수 있는 파일 사이즈 (파일의 용량)
3. property -> maxlnMemorySize : 적용된 경로에 최대로 저장할 수 있는 파일 사이즈 <!-- MultipartResolver -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="100000000"/> <!-- 10MB-->
<property name="maxInMemorySize" value="100000000"/> <!-- 10MB-->
</bean>
-jsp 설정 (화면)-
1. form 태그의 enctype을 multipart / form-data로 설정해줘야 파일업로드 기능이 적용된다.
2. input 값에 대한 타입은 file로 적용해야 한다. <!-- form enctype="multipart/form-data"를 적어줘야 한다. -->
<form method="post" action="<c:url value='/regFile'/>" enctype="multipart/form-data">
<!-- input type="file" 이라고 꼭 적어줘야 함 -->
<input type="file" class="form-control" id="uploadFile"
name="uploadFile" />
<button type="submit" class="btn btn-default">저장</button>
<button type="list" class="btn btn-default">목록</button>
</form>
java 설정 (서버) - 준비
* 업로드한 파일의 경로가 도메인 별로 달라지기 때문에 파일 저장 경로를 다르게 지정해야 한다. public class UtilFile {
String fileName = "";
// fileUpload() 메소드에서 전체 경로를 DB에 경로 그대로 저장 한다.
public String fileUpload(MultipartHttpServletRequest request,
MultipartFile uploadFile,Object obj) {
String path = "";
String fileName = "";
OutputStream out = null;
PrintWriter printWriter = null;
try {
fileName = uploadFile.getOriginalFilename();
byte[] bytes = uploadFile.getBytes();
path = getServletContext().getRealPath("/") + files/;
File file = new File(path);
// 파일명을 중복체크
if (fileName != null && !fileName.equals("")) {
if (file.exists()) {
// 파일명 앞에 구분(예)업로드 시간 초 단위)을 주어 파일명 중복을 방지한다.
fileName = System.currentTimeMillis() + "_" + fileName;
file = new File(path + fileName);
}
}
out = new FileOutputStream(file);
out.write(bytes);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (out != null) {
out.close();
}
if (printWriter != null) {
printWriter.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return path + fileName;
}
java 설정 (서버) - 적용
@Controller
public class RewardController {
// 파일을 업로드하는 컨트롤러 클래스 메소드
@RequestMapping(value = "re/add", method = RequestMethod.POST)
// 인자로 MulfiPartFile 객체,
MultipartHttpServletRequest 객체, 업로드 하려는 도메인 클래스를 받는다
public String reAddProCtrl(@RequestParam("uploadFile") MultipartFile uploadFile, MultipartHttpServletRequest request, Reward reward) {
//UtilFile 객체 생성
UtilFile utilFile = new UtilFile();
//파일 업로드 결과값을 path로 받아온다
String uploadPath=utilFile.fileUpload(request,uploadFile,
reward);
// 해당 경로만 받아 db에 저장한다.
int n = rewardService.reAddServ(uploadPath, reward);
return "isg/Boardlist";
}
}
출처 http://www.incodom.kr/spring/%ED%8C%8C%EC%9D%BC%EC%97%85%EB%A1%9C%EB%93%9C#h_c37566d71129dd68628fc71b2b2e2a15
-File 파일 업로드 관련 클래스-
File 클래스 정리
java.io 패키지는 기존의 파일이나 폴더에 대한 제어를 하는 데 사용하는 File 클래스를 제공한다.
이 클래스를 이용해서 파일과 폴더에 대한 다양한 기능을 제공한다.
파일을 나타내는 객체를 생성하려면 다음과 같은 File 클래스의 생성자 함수를 이용한다.
* File 클래스의 생성자
File 클래스의 생성자 | 설명 | File(File parent, String Child) | parent 객체 폴더의 child 라는 파일에 대한 File 객체를 생성한다. | File(String pathname) | pathname에 해당되는 파일의 File 객체를 생성한다. | File(String parent, String, child) | parent 폴더 경로의 child라는 파일에 대한 File 객체를 생성한다. | File(URI uri) | file uri 경로에 대한 파일의 File 객체를 생성한다. |
* File 클래스의 메소드
File 클래스의 메소드 | 설명 | File getAbsoluteFile() | 파일의 절대 경로를 넘겨준다. | String getAbsolutePath() | 파일의 절대 경로를 문자열로 넘겨준다. | File getCanonicalFile() | 파일의 Canonical 경로를 넘겨준다. | String getCanonicalPath() | 파일의 Canonical 경로를 문자열로 넘겨준다. | String getName() | 파일이나 폴더의 이름을 넘겨준다. | String getParent() | 부모 경로에 대한 경로명을 문자열로 넘겨준다. | File getParentFile() | 부모 폴더를 File의 형태로 리턴한다. | String getPath() | 파일의 경로를 문자열의 형태로 리턴한다. | long getTotalSpace() | 하드디스크의 총 용량을 리턴한다. | long getUsableSpace() | 하드디스크의 사용 가능한 용량을 리턴한다. | long getFreeSpace() | 하드디스크의 남은 공간을 리턴한다. | int hashCode() | hash code를 반환한다. | long lastModified() | 해당 경로 파일의 최종 수정 일자를 반환한다. | long length() | 해당 경로 파일의 길이를 반환한다. | Path toPath() | java.nio.file.Path 객체로 반환한다. | URI toURI() | URI 형태로 파일 경로를 반환한다. | File[] listRoots() | 하드디스크의 루트 경로를 반환한다. | String[] list() | 경로의 파일들과 폴더를 문자열 배열로 반환한다. | String[] list(FilenameFilter filter) | filter에 만족되는 파일들과 폴더 이름을 문자열 배열로 반환한다. | File[] listFiles() | 해당 경로의 파일들과 폴더의 파일을 배열로 반환한다. | File[] listFiles(FileFilter filter) | filter에 만족되는 파일들과 폴더를 File 배열로 반환한다. | File[] listFiles(FilenameFilter filter) | filter에 만족되는 파일들과 폴더를 File 배열로 반환한다. |
* File 생성/수정/삭제 메소드
File 생성 수정 삭제 메소드 | 설명 | boolean createNewFile() | 주어진 이름의 파일이 없으면 새로 생성한다. | static File createTempFile(String prefix, String suffix) | default temporary-file 디렉토리에 파일 이름에 prefix와 suffix를 붙여 임시파일을 생성한다. | static File createTempFile(String prefix, String suffix, File directory) | 새로운 임시파일을 파일 이름에 prefix와 suffix를 붙여 directory 폴더에 생성한다. | boolean delete() | 파일이나 폴더를 삭제한다. 단, 폴더가 비어있지 않으면 삭제할 수 없다. | void deleteOnExit() | 자바가상머신이 끝날 때 파일을 삭제한다. | boolean mkdir() | 해당 경로에 폴더를 만든다. | boolean mkdirs() | 존재하지 않는 부모 폴더까지 포함하여 해당 경로에 폴더를 만든다. | boolean renameTo(File dest) | dest 로 File 이름을 변경한다. |
* File 체크 메소드
File 체크 메소드 | 설명 | boolean exists() | 파일의 존재 여부를 리턴한다. | boolean isAbsolute() | 해당 경로가 절대경로인지 여부를 리턴한다. | boolean isDirectory() | 해당 경로가 폴더인지 여부를 리턴한다. | boolean isFile() | 해당 경로가 일반 file 인지 여부를 리턴한다. | boolean isHidden() | 해당 경로가 숨김 file 인지 여부를 리턴한다. |
* File 권한 메소드
File 클래스 권한 관련 메소드 | 설명 | boolean canExecute() | 파일을 실행할 수 있는지 여부를 리턴한다. | boolean canRead() | 파일을 읽을 수 있는지 여부를 리턴한다. | boolean canWrite() | 파일을 쓸 수 있는지 여부를 리턴한다. | boolean setExecutable(boolean executable) | 파일 소유자의 실행 권한을 설정한다. | boolean setExecutable(boolean executable, boolean ownerOnly) | 파일의 실행 권한을 소유자 또는 모두에 대해 설정한다. | boolean setReadable(boolean readable) | 파일의 소유자의 읽기 권한을 설정한다. | boolean setReadable(boolean readable, boolean ownerOnly) | 파일의 읽기 권한을 소유자 또는 모두에 대해 설정한다. | boolean setReadOnly() | 파일을 읽기 전용으로 변경한다. | boolean setWritable(boolean writable) | 파일의 소유자의 쓰기 권한을 설정한다. | boolean setWritable(boolean writable boolean ownerOnly) | 파일의 쓰기 권한을 소유자 또는 모두에 대해 설정한다 |
출처: https://hyeonstorage.tistory.com/233 [개발이 하고 싶어요]
Back-End/Problems 2019. 6. 17. 14:53
HTTP Status 500 – Internal Server Error
Type Exception Report Message <h3>Validation error messages from TagLibraryValidator for [c] in [/WEB-INF/views/home.jsp]</h3><p>56: Illegal text inside "c:choose" tag: "<!-- 초이...".</p> Description The server encountered an unexpected condition that prevented it from fulfilling the request. Exception
log 내용
ervlet.service() for servlet [appServlet] in context with path [/spring02] threw exception [<h3>Validation error messages from TagLibraryValidator for [c] in [/WEB-INF/views/home.jsp]</h3><p>56: Illegal text inside "c:choose" tag: "<!-- ch...".</p>] with root cause org.apache.jasper.JasperException: <h3>Validation error messages from TagLibraryValidator for [c] in [/WEB-INF/views/home.jsp] </h3> <p>56: Illegal text inside "c:choose" tag: "<!-- ch...".</p> at org.apache.jasper.compiler.DefaultErrorHandler.jspError(DefaultErrorHandler.java:55)
|
오류 발생 이유
<!-- -->주석은 html에서 주석을 처리하는 방식이기 때문에 jsp 코드에서는 이것을 주석으로 인식하지 않고 있는 그대로 코드를 읽기 때문에 <c:choose>태그 안에 있는 <!-- -->주석 방식 때문에 오류가 발생했음. 따라서 <!-- --> 로 처리하는 방법을 <%-- -->로 처리하는 식으로 바꾸면 오류가 발생하지 않는다.
(jsp에서는 주석처리를 <!-- -->로 해도 주석처리를 한 것과 똑같은 색깔이 되지만 실제로는 주석처리가 되지 않기 때문에 <%-- -->주석 방식을 사용해야 한다.
=> 하지만 <c:when>태그 안에도 <!-- -->가 있는데 오류가 발생하지 않음... 블로그에서는 안된다고 나와있지만 실행했을때 문제는 없었음
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | <c:choose> <!-- 초이스태그는 조건에 따른 여러곳으로 분기가 가능하다. --> <%-- 초이스태그는 조건에 따른 여러곳으로 분기가 가능하다.--> <c:when test="${sessionScope.userid == null }"> <!-- when은 test안의 값이 참일때 실행 --> <!-- userid 가 null일때 실행한다. 즉 아무것도 안들어있을때 --> <a href="${path}/member/login.do">로그인</a> | <a href="${path}/admin/login.do">관리자 로그인</a> </c:when> <c:otherwise> <!-- otherwise는 초이스태그 안에 들어가면 default문 같은 역할을 하게 된다. --> <!-- 그러니까 위의 초이스태그 안에 구문이 실행이되면 기본으로 나오게 되는 코드가 아래에 있다고 생각하면 된다. --> <!-- 로그인 중입니다. 표시와 로그아웃표시는 로그인 중에만 출력이 되야하기 때문에 oterwiser구문을 사용한다. --> ${sessionScope.name}님이 로그인중입니다. <a href="${path}/member/logout.do">로그아웃</a> </c:otherwise> </c:choose> | cs |
Back-End/Spring 2019. 6. 17. 14:01
-관리자 로그인/로그아웃 기능 구현-
-관리자 로그인 전체 구조-
( 뷰 => 컨트롤러 => 서비스 => 모델(DAO) => mapper => 컨트롤러 => 뷰) (admin) login 페이지에서 로그인 버튼을 클릭하면 id값인 "btnLogin"가
login 페이지 상부에 있는 자바스크립트 구문에 EL태그에 맵핑되서 click()메소드
안에 있는 함수가 실행되서 userid값과 passwd값을 가져와 내가 입력한 id값과 pass값과
맞는지 확인해서 일치하면 Admincontroller에 있는 login_check.do에 맵핑되어 있는 메소드와 연결한다.
맵핑된 메소드에서는 서비스를 호출하고 서비스에서는 dto를 매개값으로 받아서 DAO에 리턴한다.
DAO에서는 mybatis mapper을 호출해야하기 때문에 의존성을 주입한 sqlsession을 사용하고,
DAO 인터페이스에서 만든 메소드를 구현해서 namespace값과 id값, resultType을 확인해 일치하는
Mapper에 연결해서 sql쿼리를 (dto를 매개값으로 삼아서) sqlsession에 담는다.
다시 controller로 돌아와서 name(서비스에 담긴값을 저장한 변수)에 담긴 값이 null이 아니면 (로그인이 성공했다면..)
session에 setAttribute()메소드를 사용해서 관리자 id와 이름을 session에 저장하고,
ModelAndView 타입의 변수를 사용해서 보여줄 페이지와 보낼 값(로그인 성공 메시지)을 설정한다.
로그인이 성공하면 View (admin)페이지로 이동하고, 넘어갈때 success (메시지 값)이 같이 넘어갔기 때문에
ex) dlgkstjq12(이한섭)님 환영합니다. 와 같이 출력이 된다.
|
-관리자 로그아웃 전체 구조-
(뷰 => 컨트롤러 => 뷰)
View에 있는 logout.do와 controller에 있는 logout.do를 맵핑해서 session의 invalidate( ) 메소드를 실행한다.
invalidate( ) 메소드는 session 내부에있는 데이터를 초기화 시키는 메소드이다. 삭제 시킨후에는 redirect로 login페이지로 이동한다.
|
관리자 테이블 만들기
관리자가 로그인 한 후에 상품의 정보를 수정, 추가, 삭제 할 수 있도록 할 예정 권한에다가 1부터 9까지 주고, 예를 들면 숫자 9면 최고 관리자라는 식으로 할 수도 있다.
| create table admin ( userid varchar2(50) not null, //not null은 null값이 들어가지 못한다는 의미 passwd varchar2(50) not null, name varchar2(50) not null, email varchar2(100), join_date date default sysdate, primary key(userid) ); | cs |
| insert into admin (userid, passwd, name) values ('admin','1234','관리자'); | cs |
AdminDAO.java | package com.example.spring02.model.admin; import com.example.spring02.model.member.dto.MemberDTO; public interface AdminDAO { public String loginCheck(MemberDTO dto); //dto를 받아서 관리자 로그인을 체크하는 메소드 } | cs |
AdminDAOImpl.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | package com.example.spring02.model.admin; import javax.inject.Inject; import org.apache.ibatis.session.SqlSession; import org.springframework.stereotype.Repository; import com.example.spring02.model.member.dto.MemberDTO; @Repository //DAO를 구현한 클래스이므로 Repository 어노테이션을 사용 public class AdminDAOImpl implements AdminDAO { @Inject //mybatis mapper을 호출해야 하므로 sqlsession에 inject로 의존성을 주입하고 사용한다. SqlSession sqlSession; @Override //DAO 인터페이스에서 만든 메소드를 구현 public String loginCheck(MemberDTO dto) { return sqlSession.selectOne("admin.login_check", dto); //sqlsession에 mapper에 맵핑된 namespace와 id로 sql문을 저장한다. } } | cs |
adminMapper.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와 중복되지 않도록 네임스페이스 기재 --> <mapper namespace="admin"> <select id="login_check" resultType="String"> select name from admin where userid=#{userid} and passwd=#{passwd} </select> </mapper> | cs |
AdminService.java | package com.example.spring02.service.admin; import com.example.spring02.model.member.dto.MemberDTO; public interface AdminService { public String loginCheck(MemberDTO dto); //dto에 저장되어있는 정보를 받아 로그인을 체크하는 메소드 } | cs |
AdminServiceImpl.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | package com.example.spring02.service.admin; import javax.inject.Inject; import org.springframework.stereotype.Service; import com.example.spring02.model.admin.AdminDAO; import com.example.spring02.model.member.dto.MemberDTO; @Service //service이므로 service어노테이션을 사용함 public class AdminServiceImpl implements AdminService { @Inject AdminDAO adminDao; //dao를 호출해야하므로 inject로 의존성을 주입하고 사용 @Override public String loginCheck(MemberDTO dto) { return adminDao.loginCheck(dto); //dto에서 정보를 받고 dao에 리턴한다. } } | cs |
AdminController.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | package com.example.spring02.controller.admin; import javax.inject.Inject; import javax.servlet.http.HttpSession; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.servlet.ModelAndView; import com.example.spring02.model.member.dto.MemberDTO; import com.example.spring02.service.admin.AdminService; @Controller //컨트롤러로 사용하기위한 어노테이션 사용 @RequestMapping("/admin/*") //RequestMapping를 사용해서 공통된 부분을 맵핑 public class AdminController { @Inject AdminService adminService; //service객체를 사용해야 하므로 inject로 의존성을 주입받아서 스프링에서 관리하게 한다. @RequestMapping("login.do") // view (menu.jsp)에서 RequestMapping된 메소드 public String login() { return "admin/login"; //admin디렉터리 하위에 있는 login.jsp 파일을 보여준다는 뜻 } //view에서 login_check.do를 맵핑하면 이 메소드가 호출된다. @RequestMapping("login_check.do") public ModelAndView login_check( //이 메소드는 dto, session, mav를 매개값으로 받고, session안에 setAttribute 메소드를 사용해서 값들을 저장한다. MemberDTO dto, HttpSession session, ModelAndView mav) { //ModelAndView는 데이터를 출력할 페이지와 전송을 동시에 함 String name=adminService.loginCheck(dto); if(name != null) { //로그인 성공 (그러니까 loginCheck()메소드 안에 이름이 저장되어있다는 뜻) //dto에서 Userid()를 받아와 admin_userid라는 이름으로 session에 setAttribute()메소드를 사용해서 저장하고 //name도 마찬가지로 session에 저장한다. session.setAttribute("admin_userid", dto.getUserid()); session.setAttribute("admin_name", name); //dto에서 Userid()를 받아와 userid라는 이름으로 session에 setAttribute() 메소드를 사용해서 저장하고 //name도 마찬가지로 session에 저장한다. session.setAttribute("userid", dto.getUserid()); session.setAttribute("name", name); mav.setViewName("admin/admin"); //admin페이지를 보여준다는 뜻 mav.addObject("message", "success"); //mav안에 있는 addObject()메소드를 사용해 message라는 키에 sucess라는 value를 담아 보낸다 }else { mav.setViewName("admin/login"); //관리자 로그인이 실패했을때 보여주는 페이지 mav.addObject("message", "error"); //error메시지를 출력한다. } return mav; } //관리자 로그아웃 처리 //View에 있는 logout.do를 맵핑 @RequestMapping("logout.do") public String logout(HttpSession session) { session.invalidate(); //로그아웃을 시키려면 session에 있는 데이터를 삭제시켜야 하기 때문에 invalidate()메소드를 사용해서 //안에 있는 데이터를 초기화 시킨다. return "redirect:/admin/login.do"; //데이터를 삭제시킨후에는 login페이지로 돌아가도록 한다. } } | cs |
login.jsp (관리자용) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 | <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Insert title here</title> <!-- 관리자 로그인 페이지 --> <%@ include file="../include/header.jsp"%> <script> //button을 클릭하면 아이디와 비밀번호를 처리해서 Controller에 있는 login_check로 맵핑시킨다. //아이디와 비밀번호를 받아 처리하는 자바스크립트 구문 $(function(){ $("#btnLogin").click(function(){ //밑에 있는 button태그로 쓴 id값이 이쪽으로 맵핑되서 넘어오고, click()메소드 안에 함수가 실행 var userid=$("#userid").val(); //밑에있는 input문으로 가져온 userid의 값을 val()메소드를 사용해 가져오고, 그 값을 userid 변수에 넣는다. var passwd=$("#passwd").val(); //밑에 있는 input문으로 가져온 passwd의 값을 val()메소드를 사용해 가져오고, 그 값을 passwd 변수에 넣는다. if(userid == ""){ //userid에 아무것도 입력이 되지 않으면 alert("아이디를 입력하세요."); //경고창 출력 $("#userid").focus(); //focus()메소드는 커서를 옮겨놓는 효과, 그러니까 아이디 입력창에 자동으로 커서가 옮겨져 있는다. 깜빡이게끔 return; } if(passwd==""){ //마찬가지로 passwd가 아무것도 입력이 되지 않으면 alert("비밀번호를 입력하세요."); //경고창 출력 $("#passwd").focus(); //focus()메소드는 커서를 옮겨놓는 효과, 그러니까 아이디 입력창에 자동으로 커서가 옮겨져 있는다. 깜빡이게끔 return; } document.form1.action = "${path}/admin/login_check.do"; //밑에 form1 폼을 Controller의 login_check에 맵핑하도록 한다. document.form1.submit(); //자료를 선송 }); }); </script> </head> <body> <%@ include file="../include/menu.jsp"%> <h2>관리자 로그인</h2> <form name="form1" method="post"> <table border="1" method="post"> <tr> <td>아이디</td> <td><input id="userid" name="userid"></td> </tr> <tr> <td>비밀번호</td> <td><input type="password" id="passwd" name="passwd"></td> </tr> <tr> <td colspan="2" align="center"> <button type="button" id="btnLogin">로그인</button> <c:if test="${param.message == 'nologin' }"> <div style="color: red;">먼저 로그인하세요.</div> </c:if> <!-- c:if문 test의 값이 참이면 실행. (로그인이 아예안되어 있으면 실행)--> <!-- 로그인이 안되었다는 값이 넘어오면 빨간색으로 경고창 출력--> <c:if test="${message == 'error' }"> <div style="color: red;">아이디 또는 비밀번호가 일치하지 않습니다.</div> </c:if> <!-- c:if문 test의 값이 참이면 실행. (아이디나 비밀번호중 하나가 일치하지 않으면)--> <!-- 아이디나 비밀번호가 일치하지 않으면 빨간색으로 경고 메시지 출력--> <c:if test="${message == 'logout' }"> <div style="color: red;">로그아웃되었습니다.</div> </c:if> <!-- c:if문 test의 값이 참이면 실행. 로그아웃 메시지가 출력되면....--> <!-- 로그아웃이 되면 로그아웃되었습니다. 메시지를 출력함--> </td> </tr> </table> </form> </body> </html> | cs |
admin.jsp (관리자 로그인시 출력되는 페이지) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Insert title here</title> <%@ include file="../include/header.jsp" %> </head> <body> <%@ include file="../include/admin_menu.jsp" %> <c:if test="${message == 'success' }"> <!-- controller에서 보낸 메시지의 값이 success면 c:if문이 실행이 된다.--> <h2> ${sessionScope.admin_name} (${sessionScope.admin_userid})님 환영합니다. <!--sessionScope는 세션에 담은 setAttribute()메소드 안에 있는 값을 jsp에서 JSTL로 간단히 사용하고 싶을때 사용하면 된다. --> <!--ex) dlgkstjq12(이한섭)님 환영합니다. 와 같이 출력됨. --> </h2> </c:if> </body> </html> | cs |
Algorithm/자료구조와 알고리즘 2019. 6. 16. 15:07
-빅 오 표기법이란?-
알고리즘의 성능을 수학적으로 표기해주는 표기법 이것으로 알고리즘의 시간과 공간 복잡도를 표현할 수 있음 데이터나 사용자에 증가율에 따른 알고리즘의 성능을 예측하는 것이 목표이다.
f(n) = O(g(n)) 일때 f(x) ≤ c(상수) x g(x)
f(x) = 2x^2 + 3 일 때 g(x) = x^2
f(x) = O(g(x))?? (그러니까 O안에 어떤 숫자가 들어가야 f(x)와 g(x)가 같아지는지 증명하라는 문제)
f(x) ≤ c x g(x) 가 참이되어야 하므로 2x^2+3 ≤ c x (x^2) 가 되어야 한다. 그렇다면 c와 x에다가 무슨 값을 넣어야 위 공식이 성립이 될까? 표를 만들어서 값을 하나씩 대입해보자.
좌항계산 |
우항계산 |
결과 | x의 값 (대입한것) |
c의 값 (대입한것) |
2x^2+3 |
x^2 |
좌항이 크다. | - (궂이 x의 값을 넣지 않아도 좌항과 우항의 대소 구별이 가능함) |
1 |
2x^2+3 |
2x^2 |
좌항이 크다. | - (궂이 x의 값을 넣지 않아도 좌항과 우항의 대소 구별이 가능함) |
2 |
7 |
5 |
좌항이 크다. | 1 |
3 |
8 |
12 |
우항이 크다. | 2 |
3 |
결과적으로 x의 값에 2을 넣고, c의 값에 3을 넣었을 때 우항이 좌항보다 커진다는 사실을 알 수 있다. 결과적으로 c = 3 and x ≥ 2 일때 ,f(x) = O(g(x)) 는 참이 된다.
출처 https://www.youtube.com/watch?v=Chcl71vEkRg
|