'스프링'에 해당되는 글 7건

  1. 2019.08.20 스프링 에러 - Request method 'POST' not supported 3
  2. 2019.08.09 Spring 게시판 검색기능 구현 (내 프로젝트에 적용) 2
  3. 2019.08.06 Spring 회원가입시 이메일 인증 후 회원가입 12
  4. 2019.07.04 게시판 만들기 (게시물 수정, 파일 첨부, 첨부파일 삭제, 게시물 삭제)
  5. 2019.07.04 게시판 만들기 (댓글 쓰기 / 댓글 목록/ 댓글 갯수) 2
  6. 2019.07.02 Spring Editor (CKEditor, SummerNote) 사용 1
  7. 2019.06.19 스프링을 사용해서 pdf 생성 2

스프링 에러 - Request method 'POST' not supported

Back-End/Problems 2019. 8. 20. 11:29
728x90
반응형

에러 내용

 

11:20:35.291 [http-nio-8090-exec-8] WARN [org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver.logException:194]-

 

Resolved [org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'POST' not supported]

 

 

 

스프링에서 컨트롤러로 맵핑할때 컨트롤러에 method방식을 명시해놓고, 그 방식으로 자료를 보내지 않으면 해당 에러를 발생시킨다.

 

이런 에러가 발생했을시에는 아래와 같이 post방식을 지원할 수 있도록 컨트롤러에 해당 메소드에 RequestMethod.POST 방식을 추가해주면 된다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@RequestMapping(value = "/board/view.do", method= {RequestMethod.GET, RequestMethod.POST}) //POST방식으로도 맵핑할 수 있도록 코드를 추가하였다.
    public ModelAndView view(@RequestParam int member_bno,
            @RequestParam int curPage,
            @RequestParam String search_option,
            @RequestParam String keyword,
            HttpSession session) throws Exception{
        
        //조회수 증가 쿼리
        memberboardservice.increaseViewcnt(member_bno, session);
        
        ModelAndView mav = new ModelAndView();
        mav.setViewName("board/memberboardview");
        
        //view로 자료를 넘기기위해서 mav에 값들을 저장해서 view.jsp로 리턴시킨다.
        mav.addObject("dto", memberboardservice.read(member_bno)); //상세보기를 한번 클릭하면 조회수를 1증가시킨다.
        mav.addObject("curPage", curPage);
        mav.addObject("search_option", search_option);
        mav.addObject("keyword", keyword);
        
        return mav;     //view로 넘어가서 출력이 된다.
    }
cs

아래 책은 제가 공부할때 활용했던 책으로 추천드리는 책이니 한번씩 읽어보시는것을 추천드립니다!! ㅎㅎ

토비의 스프링 3.1 세트:스프링의 이해와 원리 + 스프링의 기술과, 에이콘출판

이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.

 

728x90
반응형
:

Spring 게시판 검색기능 구현 (내 프로젝트에 적용)

Back-End/Spring 2019. 8. 9. 17:15
728x90
반응형

검색창에서 작성자, 제목, 내용, 작성자+내용+제목의 옵션으로 글을 검색 할 수 있게 검색기능구현함

 

 

1.  게시판 view 페이지에 검색기능 관련 폼 태그 추가

 

memberboard.jsp 중 일부

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
 
//컨트롤러의 list.do로 맵핑되고, user_id, title, content값을 매개값으로 넘긴다.
 
//검색옵션은 작성자, 제목, 내용, 작성자+제목+내용으로 검색할 수 있도록 한다.
 
<form name="form1" method="post" action="list.do">
 
    <select name="search_option">
        <option value="user_id"
<c:if test="${map.search_option == 'user_id'}">selected</c:if>
>작성자</option>
 
        <option value="title" 
<c:if test="${map.search_option == 'title'}">selected</c:if>
        >제목</option>
 
        <option value="content" 
<c:if test="${map.search_option == 'content'}">selected</c:if>
        >내용</option>
 
        <option value="all" 
<c:if test="${map.search_option == 'all'}">selected</c:if>
        >작성자+내용+제목</option>
 
    </select>
    <input name="keyword" value="${map.keyword}">
    <input type="submit" value="조회">
</form>
cs

 

 

MemberBoardController.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
@RequestMapping("list.do")    //세부적인 url mapping
    public ModelAndView list(//RequestParam으로 옵션, 키워드, 페이지의 기본값을 각각 설정해준다.
            
            @RequestParam(defaultValue="1"int curPage,
 
            @RequestParam(defaultValue="user_id"String search_option, //기본 검색 옵션값을 작성자로 한다.
 
            @RequestParam(defaultValue=""String keyword //키워드의 기본값을 ""으로 한다.
 
            )
             throws Exception{
        
        //레코드 갯수를 계산
        int count = 1000;
        
        //페이지 관련 설정, 시작번호와 끝번호를 구해서 각각 변수에 저장한다.
        Pager pager = new Pager(count, curPage);
        int start = pager.getPageBegin();
        int end =  pager.getPageEnd();
             
//map에 저장하기 위해 list를 만들어서 검색옵션과 키워드를 저장한다.
        List<MemberBoardDTO> list = memberboardservice.listAll(search_optionkeyword, start, end);
        
        ModelAndView mav = new ModelAndView();
        Map<String,Object> map = new HashMap<>();    //넘길 데이터가 많기 때문에 해쉬맵에 저장한 후에 modelandview로 값을 넣고 페이지를 지정
        
        map.put("list", list);                         //map에 list(게시글 목록)을 list라는 이름의 변수로 자료를 저장함.
        map.put("pager", pager);
        map.put("count", count);
        map.put("search_option", search_option);
        map.put("keyword", keyword);
        mav.addObject("map", map);                    //modelandview에 map를 저장
        
        System.out.println("map : "+map);
        mav.setViewName("board/memberboard");                //자료를 넘길 뷰의 이름
        
        return mav;    //게시판 페이지로 이동
    
    }
cs

 

 

 

게시판 목록 기능 구현할때와 동일하게 서비스 -> dao를 거쳐서 mapper로 이동

 

boardMapper.xml 

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
<?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="memberboard">
    
    <!-- rownum을 rn이란 문자로 줄여쓴다. 밑에 from문을 A로 줄여쓴다.  -->
                  <!-- 이 from문이 먼저 실행된 다음에 번호를 붙였기 때문에 일련번호가 다시 새로 매겨졌다. -->
                <!--  이 안쪽의 쿼리가 가장 중요함 -->
                
                
<select id="listAll" resultType="com.example.hansub_project.model.board.dto.MemberBoardDTO">
<!-- 결과는 boardDTO타입이 된 -->
        <include refid="paging_header" /
        
        <!-- ref는 다른테이블을 의미한다. -->
        <!-- 번호, 제목, 작성자, 이름, 날짜, 조회수 , 그리고 댓글의 갯수를 검색 -->
        <!-- board 테이블과 member 테이블로 부터 검색 -->
            select member_bno, user_id, reg_date, viewcnt, title, rcnt, content, recommend            
            from member_board
            <!-- bno의 내림차순으로 검색 -->
            <!-- where절은 (조건)은 include 태그를 이용했음 -->
        <include refid="search" />
            order by member_bno desc
        <include refid="paging_footer" />        
    </select>
    
    
    <sql id="paging_header">
    <!-- 게시물을 한페이지에 10개씩 볼 수 있게하는 쿼리 윗부분-->
        select *
        from (
            select rownum as rn, A.*
            from (    
    </sql>
    
    
    <sql id="paging_footer">
    <!-- 게시물을 한페이지에 10개씩 볼 수 있게하는 쿼리  아랫 부분-->
    <!-- 새로 매겨진 일련번호 1~10번 글까지 1페이지 -->
    <!-- 11~20번 글까지 2페이지.. -->
            ) A
        ) where rn between #{start} and #{end}    
    </sql>
    
 
    <sql id="search">
        <choose>
          
//작성자+제목+내용의 검색조건으로 게시물을 검색하는 쿼리
            <when test="search_option == 'all' ">
                where  
                      user_id like '%'||#{keyword}||'%'
                      or content like '%' || #{keyword}||'%'
                      or title like '%'||#{keyword}||'%'   
            </when>
            <otherwise>
 
//내가 지정한 조건 (작성자, 제목, 내용) 의 검색조건으로 게시물을 검색하는 쿼리
                where ${search_option} like '%'||#{keyword}||'%'
            </otherwise>
        </choose>
    </sql>
 
 
</mapper>
 
cs

 

 

 

아래 책은 제가 공부할때 활용했던 책으로 추천드리는 책이니 한번씩 읽어보시는것을 추천드립니다!! ㅎㅎ

토비의 스프링 3.1 세트:스프링의 이해와 원리 + 스프링의 기술과, 에이콘출판

이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.

728x90
반응형
:

Spring 회원가입시 이메일 인증 후 회원가입

Back-End/Spring 2019. 8. 6. 15:58
728x90
반응형

 

 기본 구조


 1. 메인페이지에서 "회원가입" 을 클릭


 2. 이메일 인증 페이지에서 이메일을 작성후 인증코드 전송 버튼을 클릭


 3. 입력한 이메일에 들어가서 메일로 도착한 인증코드를 인증코드 입력창에 입력함


 4. 인증코드가 맞으면 회원가입 창으로 이동하고, 인증코드가 틀리면 경고창을 출력한 후에 다시 입력하게 한다.





1. pom.xml에 이메일 관련 라이브러리를 추가함


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<!-- 메일 전송 -->
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-context-support -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context-support</artifactId>
    <version>${org.springframework-version}</version>
</dependency>
    
    
    <!-- https://mvnrepository.com/artifact/com.sun.mail/javax.mail -->
<dependency>
    <groupId>com.sun.mail</groupId>
    <artifactId>javax.mail</artifactId>
    <version>1.6.2</version>
</dependency>
    
    
    <dependency>
    <groupId>javax.mail</groupId>
    <artifactId>mail</artifactId>
    <version>1.4</version>
</dependency>
cs




2. root-context.xml에 사용할 이메일에 대한 빈 작성 (나같은 경우는 gmail을 사용함)


1
2
3
4
5
6
7
8
9
10
11
12
13
<!-- Gmail -->
  <bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
    <property name="host" value="smtp.gmail.com" />
    <property name="port" value="587" />
    <property name="username" value="아이디@gmail.com" />
    <property name="password" value="비밀번호" />
    <property name="javaMailProperties">
    <props>
      <prop key="mail.smtp.auth">true</prop>
      <prop key="mail.smtp.starttls.enable">true</prop>
    </props>
    </property>
  </bean>
cs




3. view 파일들 작성


email.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
<%@ 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>
</head>
<body>
 
 
 
<table border="1" width="300" height="300" align"center">
<center>
<span style="color: green; font-weight: bold;">이메일 인증 (이메일을 인증 받아야 다음 단계로 넘어갈 수 있습니다.)</span> <br> <br>    
        <br> <br>
        
        
 
        
        <div style="text-align:center;">
            <tr>        
                <td>
                <center>
                    <form action="auth.do" method="post">
                    
                    <center>
                        <br>
                        <div>
                            이메일 : <input type="email" name="e_mail"
                                placeholder="  이메일주소를 입력하세요. ">
                        </div>                                                    
 
                        <br> <br>
                        <button type="submit" name="submit">이메일 인증받기 (이메일 보내기)</button>
 
                        </div>
                    </td>
                </tr>
                    </center>
            </table>
        </form>
</center>
 
</body>
</html>
cs




email_injeung.jsp (인증번호를 입력하는 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
<%@ 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>
</head>
<body>
 
<table border="1" width="300" height="300" align"center">
<center>
<span style="color: green; font-weight: bold;">입력한 이메일로 받은 인증번호를 입력하세요. (인증번호가 맞아야 다음 단계로 넘어가실 수 있습니다.)</span> <br> <br>    
        <br> <br>
        
        
        <div style="text-align:center;">
            <tr>        
                <td>
                <center>
                    <form action="join_injeung.do${dice}" method="post"> //받아온 인증코드를 컨트롤러로 넘겨서 일치하는지 확인                  
                    <center>
                        <br>
                        <div>
                            인증번호 입력 : <input type="number" name="email_injeung"
                                placeholder="  인증번호를 입력하세요. ">
                        </div>                                        
 
                        <br> <br>
                        <button type="submit" name="submit">인증번호 전송</button>
 
                        </div>
                    </td>
                </tr>
                    </center>
            </table>
        </form>
</center>
 
 
</body>
</html>
cs




4. 컨트롤러 작성 (MemberController.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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
@Controller    //컨트롤러 빈 선언
public class MemberController {
    
    
    @Inject    //서비스를 호출하기 위해서 의존성을 주입
    JavaMailSender mailSender;     //메일 서비스를 사용하기 위해 의존성을 주입함.
    MemberService memberservice; //서비스를 호출하기 위해 의존성을 주입
    
    
    
    
    //로깅을 위한 변수
    private static final Logger logger=
    LoggerFactory.getLogger(MemberController.class);
    private static final String String = null;
    
    
    // mailSending 코드
        @RequestMapping( value = "/member/auth.do" , method=RequestMethod.POST )
        public ModelAndView mailSending(HttpServletRequest request, String e_mail, HttpServletResponse response_email) throws IOException {
 
            Random r = new Random();
            int dice = r.nextInt(4589362+ 49311; //이메일로 받는 인증코드 부분 (난수)
            
            String setfrom = "dlgkstjq623@gamil.com";
            String tomail = request.getParameter("e_mail"); // 받는 사람 이메일
            String title = "회원가입 인증 이메일 입니다."// 제목
            String content =
            
            System.getProperty("line.separator")+ //한줄씩 줄간격을 두기위해 작성
            
            System.getProperty("line.separator")+
                    
            "안녕하세요 회원님 저희 홈페이지를 찾아주셔서 감사합니다"
            
            +System.getProperty("line.separator")+
            
            System.getProperty("line.separator")+
    
            " 인증번호는 " +dice+ " 입니다. "
            
            +System.getProperty("line.separator")+
            
            System.getProperty("line.separator")+
            
            "받으신 인증번호를 홈페이지에 입력해 주시면 다음으로 넘어갑니다."// 내용
            
            
            try {
                MimeMessage message = mailSender.createMimeMessage();
                MimeMessageHelper messageHelper = new MimeMessageHelper(message,
                        true"UTF-8");
 
                messageHelper.setFrom(setfrom); // 보내는사람 생략하면 정상작동을 안함
                messageHelper.setTo(tomail); // 받는사람 이메일
                messageHelper.setSubject(title); // 메일제목은 생략이 가능하다
                messageHelper.setText(content); // 메일 내용
                
                mailSender.send(message);
            } catch (Exception e) {
                System.out.println(e);
            }
            
            ModelAndView mv = new ModelAndView();    //ModelAndView로 보낼 페이지를 지정하고, 보낼 값을 지정한다.
            mv.setViewName("/member/email_injeung");     //뷰의이름
            mv.addObject("dice", dice);
            
            System.out.println("mv : "+mv);
 
            response_email.setContentType("text/html; charset=UTF-8");
            PrintWriter out_email = response_email.getWriter();
            out_email.println("<script>alert('이메일이 발송되었습니다. 인증번호를 입력해주세요.');</script>");
            out_email.flush();
            
            
            return mv;
            
        }
    
    //이메일 인증 페이지 맵핑 메소드
    @RequestMapping("/member/email.do")
    public String email() {
        return "member/email";
    }
    
    
    //이메일로 받은 인증번호를 입력하고 전송 버튼을 누르면 맵핑되는 메소드.
    //내가 입력한 인증번호와 메일로 입력한 인증번호가 맞는지 확인해서 맞으면 회원가입 페이지로 넘어가고,
    //틀리면 다시 원래 페이지로 돌아오는 메소드
    @RequestMapping(value = "/member/join_injeung.do{dice}", method = RequestMethod.POST)
    public ModelAndView join_injeung(String email_injeung, @PathVariable String dice, HttpServletResponse response_equals) throws IOException {
 
        
        
        
        System.out.println("마지막 : email_injeung : "+email_injeung);
        
        System.out.println("마지막 : dice : "+dice);
        
//페이지이동과 자료를 동시에 하기위해 ModelAndView를 사용해서 이동할 페이지와 자료를 담음
        ModelAndView mv = new ModelAndView();
        
        mv.setViewName("/member/join.do");
        
        mv.addObject("e_mail",email_injeung);
        
        if (email_injeung.equals(dice)) {
            
            //인증번호가 일치할 경우 인증번호가 맞다는 창을 출력하고 회원가입창으로 이동함
            
            
            
            mv.setViewName("member/join");
            
            mv.addObject("e_mail",email_injeung);
            
            //만약 인증번호가 같다면 이메일을 회원가입 페이지로 같이 넘겨서 이메일을
            //한번더 입력할 필요가 없게 한다.
            
            response_equals.setContentType("text/html; charset=UTF-8");
            PrintWriter out_equals = response_equals.getWriter();
            out_equals.println("<script>alert('인증번호가 일치하였습니다. 회원가입창으로 이동합니다.');</script>");
            out_equals.flush();
    
            return mv;
            
            
        }else if (email_injeung != dice) {
            
            
            ModelAndView mv2 = new ModelAndView(); 
            
            mv2.setViewName("member/email_injeung");
            
            response_equals.setContentType("text/html; charset=UTF-8");
            PrintWriter out_equals = response_equals.getWriter();
            out_equals.println("<script>alert('인증번호가 일치하지않습니다. 인증번호를 다시 입력해주세요.'); history.go(-1);</script>");
            out_equals.flush();
            
    
            return mv2;
            
        }    
    
        return mv;
        
    }
cs




5. MailHandler.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
package com.example.hansub_project;
 
import java.io.UnsupportedEncodingException;
 
import javax.activation.DataSource;
import javax.mail.MessagingException;
import javax.mail.internet.MimeMessage;
 
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
 
public class MailHandler {
    
    
    private JavaMailSender mailSender;
    private MimeMessage message;
    private MimeMessageHelper messageHelper;
 
 
    public MailHandler(JavaMailSender mailSender) throws MessagingException {
        this.mailSender = mailSender;
        message = this.mailSender.createMimeMessage();
        messageHelper = new MimeMessageHelper(message, true"UTF-8");
    }
 
 
    public void setSubject(String subject) throws MessagingException {
        messageHelper.setSubject(subject);
        
        // 이메일 타이틀 
    }
    
    public void setText(String htmlContent) throws MessagingException {
        messageHelper.setText(htmlContent, true);
        
        //  이메일 TEXT 부분 
    }
    
    public void setFrom(String email, String name) throws UnsupportedEncodingException, MessagingException {
        messageHelper.setFrom(email, name);
        // 보내는 사람 이메일 
    }
    
    public void setTo(String email) throws MessagingException {
        messageHelper.setTo(email);
        //받는 사람 이메일 
    }
    
    public void addInline(String contentId, DataSource dataSource) throws MessagingException {
        messageHelper.addInline(contentId, dataSource);
    }
    
    public void send() {
        try {
            mailSender.send(message);
        }catch (Exception e) {
            e.printStackTrace();
        }
    }
}
 
cs




6. MemberDTO


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
package com.example.hansub_project.model.member.dto;
 
import java.util.Date;
 
public class MemberDTO {
    
    private String user_id;    //아이디
    private String member_pass;    //비밀번호
    private String e_mail;    //이메일
    private Date join_date;    //가입일자
    
    
    
    public String getUser_id() {
        return user_id;
    }
    public void setUser_id(String user_id) {
        this.user_id = user_id;
    }
    public String getMember_pass() {
        return member_pass;
    }
    public void setMember_pass(String member_pass) {
        this.member_pass = member_pass;
    }
    public String getE_mail() {
        return e_mail;
    }
    public void setE_mail(String e_mail) {
        this.e_mail = e_mail;
    }
    public Date getJoin_date() {
        return join_date;
    }
    public void setJoin_date(Date join_date) {
        this.join_date = join_date;
    }
    
    
    @Override
    public String toString() {
        return "MemberDTO [user_id=" + user_id + ", member_pass=" + member_pass + ", e_mail=" + e_mail + ", join_date="
                + join_date + "]";
    }
    
 
}
 
cs




7. 서비스 , dao, mapper


MemberService.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
package com.example.hansub_project.service.member;
 
import java.util.List;
import java.util.Map;
 
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
 
import com.example.hansub_project.model.member.dto.MemberDTO;
 
 
public interface MemberService {
        
    
    public void join (Map<String, Object>map,MemberDTO dto); //회원가입 관련
    
    
    public boolean loginCheck(MemberDTO dto, HttpSession session);    //로그인 관련
    
    
    public String find_idCheck(MemberDTO dto);    //아이디 찾기 관련
    
    
    public String find_passCheck(MemberDTO dto);    //비밀번호 찾기 관련
    
    
    public void authentication(MemberDTO dto);        //회원 인증관련 메소드
    
    
    public void pass_change(Map<String, Object> map, MemberDTO dto)throws Exception;    //비밀번호 변경
    
    
    public boolean email_check(String e_mail) throws Exception;    //이메일 중복확인을 하는 메소드
    
    
    public boolean join_id_check(String user_id) throws Exception;    //회원가입시 아이디를 체크하는 메소드
    
    
    public List<MemberDTO> member_profile(String user_id) throws Exception;    //회원의 프로필을 볼 수 있는 메소드
    
    
 
}
 
cs




MemberServiceImpl.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.hansub_project.service.member;
 
import java.io.PrintWriter;
import java.util.List;
import java.util.Map;
 
import javax.inject.Inject;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
 
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
 
import com.example.hansub_project.MailHandler;
import com.example.hansub_project.model.member.dao.MemberDAO;
import com.example.hansub_project.model.member.dto.MemberDTO;
 
@Service //서비스 빈 선언
public class MemberSerivceImpl implements MemberService {
 
    
    @Inject    
    MemberDAO memberdao; //dao를 사용하기 위해 의존성을 주입
    private JavaMailSender mailSender;
 
    
    
    @Override    //회원가입 메소드, Map과 dto를 갖이 넘김
    public void join(Map<String, Object>map,MemberDTO dto) {
        memberdao.join(map,dto);
 
    }
 
 
    @Override    //로그인 관련 메소드 (세션에 아이디와 비밀번호를 저장)
    public boolean loginCheck(MemberDTO dto, HttpSession session) {
        
        boolean result = memberdao.loginCheck(dto);
        if(result) {    //로그인 성공
            session.setAttribute("user_id", dto.getUser_id());
            session.setAttribute("member_pass", dto.getMember_pass());
            System.out.println(session.getAttribute("user_id"));
            System.out.println(session.getAttribute("member_pass"));
        }
        
        return result;
    }
 
    //아이디 찾기
    @Override
    public String find_idCheck(MemberDTO dto) {
        String id = memberdao.find_idCheck(dto);
        
        return id;
    }
 
    //비밀번호 찾기
    @Override
    public String find_passCheck(MemberDTO dto) {
        String pass = memberdao.find_passCheck(dto);
        return pass;
    }
 
 
    @Override
    public void authentication(MemberDTO dto) {
        
        memberdao.authentication(dto);
    }
 
 
    @Override
    public void pass_change(Map<String, Object> map, MemberDTO dto) throws Exception {
        
        
        memberdao.pass_change(map,dto);
    }
 
 
    //이메일 중복 확인
    @Override
    public boolean email_check(String e_mail) throws Exception{
        
        boolean result = memberdao.email_check(e_mail);
        
        return result;
        
    }
 
    //아이디 중복 확인
    @Override
    public boolean join_id_check(String user_id) throws Exception {
    
        boolean result = memberdao.join_id_check(user_id);
        
        return result;
    }
 
 
    //자신의 프로필을 볼 수 있게 하는 메소드
    @Override
    public List<MemberDTO> member_profile(String user_id) throws Exception{
        
        return memberdao.member_profile(user_id);
    }
    
 
    
}
cs




MemberDAO.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
package com.example.hansub_project.model.member.dao;
 
import java.util.HashMap;
import java.util.List;
import java.util.Map;
 
import com.example.hansub_project.model.member.dto.MemberDTO;
 
public interface MemberDAO {
 
    public void join(Map<String, Object>map,MemberDTO dto);     //회원가입 관련
    
    public boolean loginCheck(MemberDTO dto);        //로그인 관련
    
    public String find_idCheck(MemberDTO dto);        //아이디 찾기
    
    public String find_passCheck(MemberDTO dto);    //비밀번호 찾기
 
    public void authentication(MemberDTO dto);        //소셜 로그인 회원인증 관련 메소드
 
    public void pass_change(Map<String, Object> map, MemberDTO dto)throws Exception;    //비밀번호 변경
 
    public boolean email_check(String e_mail) throws Exception;    //이메일 중복 확인
 
    public boolean join_id_check(String user_id)throws Exception;    //아이디 중복 확인
 
    public List<MemberDTO> member_profile(String user_id) throws Exception;    //회원의 프로필 정보를 확인할 수 있는 메소드
    
}
 
cs




MemberDAOImpl.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
package com.example.hansub_project.model.member.dao;
 
 
import java.util.HashMap;
import java.util.List;
import java.util.Map;
 
import javax.inject.Inject;
import javax.mail.Session;
 
import org.apache.ibatis.session.SqlSession;
import org.springframework.stereotype.Repository;
 
import com.example.hansub_project.model.member.dto.MemberDTO;
 
 
@Repository
public class MemberDAOImpl implements MemberDAO {
 
    
    @Inject
    SqlSession sqlSession;
    
    
    //회원가입 관련 메소드
    @Override
    public void join(Map<String, Object>map, MemberDTO dto) {
 
        map.get("user_id");
        map.get("member_pass");
        map.get("e_mail");
        
        sqlSession.insert("member.insertUser",map);        
    }
    
    
    //로그인관련 메소드
    @Override
    public boolean loginCheck(MemberDTO dto) {
        String name
            =sqlSession.selectOne("member.login_check", dto);
        
        //조건식 ? true일때의 값 : false일때의 값
        return (name==null) ? false : true;
    }
 
    
    //아이디 찾기 관련 메소드
    @Override
    public String find_idCheck(MemberDTO dto) {
        String id = sqlSession.selectOne("member.find_id_check", dto);
        return id;
        
    }
 
    
    //비밀번호 찾기 관련 메소드
    @Override
    public String find_passCheck(MemberDTO dto) {
        String pass = sqlSession.selectOne("member.find_pass_check", dto);
        return pass;
    }
 
    
    //회원 인증 관련 메소드
    //버튼을 클릭한 회원의 정보를 회원 테이블에 저장해서 사용할 수 있게 함
    @Override
    public void authentication(MemberDTO dto) {
        
        sqlSession.insert("member.authentication", dto);
        
    }
 
 
    @Override
    public void pass_change(Map<String, Object> map, MemberDTO dto)throws Exception{
        
        map.get("member_pass");
        map.get("e_mail");
 
        sqlSession.update("member.pass_change", map);
    }
 
 
    @Override
    public boolean email_check(String e_mail) throws Exception {
        String email
        =sqlSession.selectOne("member.email_check", e_mail);
    
        //조건식 ? true일때의 값 : false일때의 값
        return (email==null) ? true : false;
        
    }
 
 
    @Override
    public boolean join_id_check(String user_id) throws Exception {
        String user_id1
        =sqlSession.selectOne("member.join_id_check", user_id);
    
        //조건식 ? true일때의 값 : false일때의 값
        return (user_id1==null) ? true : false;
    }
 
    
    //회원의 프로필 정보를 리턴한다.
    @Override
    public List<MemberDTO> member_profile(String user_id) throws Exception {
        
        return sqlSession.selectList("member.member_profile", user_id);
    }
    
}
 
cs




memberMapper.xml


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
<?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="member">
    
    <!-- 회원가입 mapper -->
    <insert id="insertUser" parameterType="hashMap">
    insert into member (USER_ID, MEMBER_PASS, E_MAIL)
    values (#{user_id}, #{member_pass}, #{e_mail})
    </insert>
    
    
    <!-- 로그인 관련 mapper-->
    <select id = "login_check" parameterType=
    "com.example.hansub_project.model.member.dto.MemberDTO"
    resultType="String">
        select user_id from member
        where user_id=#{user_id} and member_pass=#{member_pass}
    </select>    
    
    
    <!-- 아이디 찾기 관련 mapper -->
    <select id = "find_id_check" parameterType=
    "com.example.hansub_project.model.member.dto.MemberDTO"
    resultType="String">
        select user_id from member
        where e_mail=#{e_mail}
    </select>
    
    <!-- 비밀번호 찾기 관련 mapper -->
    <select id = "find_pass_check" parameterType=
    "com.example.hansub_project.model.member.dto.MemberDTO"
    resultType="String">
        select member_pass from member
        where user_id=#{user_id} and e_mail=#{e_mail}
    </select>
    
    
    <!-- 소셜 로그인 관련 mapper -->
    <!-- 소셜 로그인 한 후에 회원 인증 버튼을 누르면 소셜 로그인 api에서 받아온 정보를 데이터 베이스의 member테이블에 저장하도록 하는 쿼리 -->
    <insert id="authentication" parameterType="com.example.hansub_project.model.member.dto.MemberDTO">
    insert into member (USER_ID, MEMBER_PASS, E_MAIL)
    values (#{user_id}, 0, #{e_mail})
    </insert>
    
    
    <!-- 비밀번호 변경 관련 mapper -->
    <update id = "pass_change" parameterType="hashMap">
    update member set member_pass=#{member_pass} where e_mail=#{e_mail}
    </update>
    
    
    <!-- 이메일 중복확인 관련 mapper-->
    <select id = "email_check" resultType="String">
        select e_mail from member
        where e_mail=#{e_mail}
    </select>
    
    
    <!-- 아이디 중복확인 관련 mapper-->
    <select id = "join_id_check" resultType="String">
        select user_id from member
        where user_id=#{user_id}
    </select>        
    
    
    <!-- 회원 프로필 확인 mapper -->
    <select id = "member_profile" resultType="com.example.hansub_project.model.member.dto.MemberDTO">
    select user_id, e_mail, join_date
    from member
    where user_id=#{user_id}
    </select>
    
    
</mapper>
 
cs






728x90
반응형
:

게시판 만들기 (게시물 수정, 파일 첨부, 첨부파일 삭제, 게시물 삭제)

Back-End/Spring 2019. 7. 4. 18:19
728x90
반응형

첨부파일이 저장되는 테이블을 작성



테이블이 중복될수 있으므로 테이블과 테이블에 관련된 제약조건을 삭제

1
drop table attach cascade constraints;
cs


테이블 생성
1
2
3
4
5
6
create table attach (
    fullName varchar2(150not null, //첨부파일 이름, null값 방지, 파일이름은 uuid를 이용해서 중복되지 않도록 할 예정
    bno number not null, //게시글 번호, null값 방지
    regdate date default sysdate, //등록날짜, 현재시간으로 설정
    primary key(fullName) //기본키를 첨부파일이름으로 설정
);
cs



attach테이블의 bno 속성(글번호)이 board테이블에 bno 속성 (글번호)를 참조하도록 외래키로 설정함. (제약조건 설정)

(게시글 번호가 꼬이면 안되기 때문, 게시글이 삭제되면 같이 삭제될수 있게끔...)

1
2
alter table attach add constraint fk_board_attach //fk_board_attach는 제약조건의 이름
foreign key (bno) references board(bno);
cs



중복될 수 있으므로 먼저 시퀀스를 삭제

1
drop sequence seq_board;
cs



board 테이블의 bno 컬럼을 위한 시퀀스를 생성

1
2
3
create sequence seq_board
start with 1 //시작값을 1로하고
increment by 1; //1씩 증가하도록 설정함
cs



===============================================================================================



view.jsp 페이지에서 common.js를 include 해야한다.

1
<script src="${path}/include/js/common.js"></script>
cs



view.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
$(".fileDrop").on("dragenter dragover",function(e){
        //기본 효과 막음, 기본효과가 있으면 이미지 파일이 실행되어 버림
        e.preventDefault();
    });
    $(".fileDrop").on("drop",function(e){
        e.preventDefault();
        //첫번째 첨부파일
//드롭한 파일을 폼 데이터에 추가함
        var files=e.originalEvent.dataTransfer.files;
        var file=files[0];
        //폼 데이터에 첨부파일 추가 (0번 인덱스이므로 첫번째 파일만 붙였다.)
        var formData=new FormData();
        formData.append("file",file);
        $.ajax({ //비동기 방식으로 호출
            url: "${path}/upload/uploadAjax"// uploadAjax를 호출함
            data: formData,  // formData를 보내고                   
            dataType: "text", // text 타입으로 보낸다.
            processData: false, // 요청으로 보낸 데이터를 query string 형태로 변환할지 여부
            contentType: false, // 서버로 보내지는 데이터의 기본값
            type: "post",
//호출처리가 완료된 다음 (성공한 후)에 실행되는 구문
//컨트롤러에서 업로드 경로와 상태코드 (200)을 리턴해서 이쪽으로 보낸다.
            success: function(data){ //콜백 함수
                //console.log(data);
                //data : 업로드한 파일 정보와 Http 상태 코드
                var fileInfo=getFileInfo(data); //첨부파일의 정보
                //console.log(fileInfo);
                var html="<a href='"+fileInfo.getLink+"'>"+
                    fileInfo.fileName+"</a><br>";
                html += "<input type='hidden' class='file' value='"
                    +fileInfo.fullName+"'>"; //hidden 태그를 추가
                $("#uploadedList").append(html); //div에 추가
            }
        });
    });
cs




AjaxUploadController.java

1
2
3
4
5
6
7
8
9
10
    // 업로드한 파일은 MultipartFile 변수에 저장됨
    @ResponseBody // json 형식으로 리턴
    @RequestMapping(value = "/upload/uploadAjax"
    method = RequestMethod.POST, produces = "text/plain;charset=utf-8")
    public ResponseEntity<String> uploadAjax(MultipartFile file) throws Exception {
       //파일의 정보를 로그에 출력
logger.info("originaName:"
+file.getOriginalfilename());
logger.info("size:" +file.getSize());
logger.info("contentType:" +file.getContentType());
//new ResponseEntity (데이터, 상태코드)
//new ResponseEntity (업로드된 파일이름, 상태코드)

        return new ResponseEntity<String>(
                UploadFileUtils.uploadFile(uploadPath, file.getOriginalFilename(), file.getBytes()), HttpStatus.OK);
    }
 
cs



view.jsp 중 일부

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//목록 버튼
    $("#btnList").click(function(){
        location.href="${path}/board/list.do";
    });
    
    //수정 버튼
    $("#btnUpdate").click(function(){
        //첨부파일 이름들을 폼에 추가
        var str="";
        //id가 uploadList인것들 (div)에 클래스에 file인것 각각 (each) 
        $("#uploadedList .file").each(function(i){
            
            str+="<input type='hidden' name='files["+i+"]' value='"
                +$(this).val()+"'>";
                //파일이름에다 인덱스 번호를 하나씩 붙인다.
        });
        
        //폼에 hidden 태그들을 추가함
        $("#form1").append(str);
        
        document.form1.action="${path}/board/update.do"//위에서 만든 폼을 가지고 update.do로 보낸다.
        document.form1.submit();
    });
cs


 

지금까지 보낸 내용들이 dto안에 다 쌓인다.


BoardServiceImpl.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
package com.example.spring02.service.board;
 
import java.util.List;
 
import javax.inject.Inject;
import javax.servlet.http.HttpSession;
 
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
 
import com.example.spring02.model.board.dao.BoardDAO;
import com.example.spring02.model.board.dto.BoardDTO;
 
@Service // service bean
public class BoardServiceImpl implements BoardService {
 
    @Inject //dao를 호출하기 때문에 의존성을 주입
    BoardDAO boardDao; 
 
    //첨부파일 레코드 삭제
    @Override
    public void deleteFile(String fullName) {
        boardDao.deleteFile(fullName); 
    }
 
    @Override
    public List<String> getAttach(int bno) {
        return boardDao.getAttach(bno);  
    }
    
    // 1.글쓰기 - 게시물 번호 생성
    
    // 2.첨부파일 등록-게시물 번호 사용
    
    @Transactional
    @Override
    public void create(BoardDTO dto) throws Exception {
        //board 테이블에 레코드 추가
        boardDao.create(dto); 
        //attach 테이블에 레코드 추가
        String[] files=dto.getFiles(); //첨부파일 이름 배열
        if(files==nullreturn;  //첨부파일이 없으면 skip
        for(String name : files) {
            boardDao.addAttach(name);  //attach 테이블에 insert
        }
    }
 
    @Override
    public BoardDTO read(int bno) throws Exception {
        return boardDao.read(bno);
    }
 
    @Transactional //트랜잭션 처리 method
    //코드 수정과 첨부파일을 첨부하는 기능이 동시에 같이 들어가야하기 때문에
//일관성을 유지하기 위해서 트랜잭션 처리를 실시한다.
//만약 두개중에 하나라도 되지않으면 작업을 취소시키기고, 롤백을 한다.
    @Override
    public void update(BoardDTO dto) throws Exception {
        boardDao.update(dto); //board 테이블 수정
        //attach 테이블 수정
        String[] files=dto.getFiles();
        if(files==nullreturn;
        for(String name : files) {
            System.out.println("첨부파일 이름:"+name);
            boardDao.updateAttach(name, dto.getBno()); 
        }
    }
 
    @Transactional
    @Override
    public void delete(int bno) throws Exception {
        //reply 레코드 삭제
        //attach 레코드 삭제
        //첨부파일 삭제
        //board 레코드 삭제
        boardDao.delete(bno); 
    }
 
    @Override
    public List<BoardDTO> listAll(
            //매개변수는 시작 레코드번호, 끝번호, 옵션과 키워드가 들어간다
String search_option, String keyword,int start, int end)
            throws Exception {
        return boardDao.listAll(search_option,keyword,start,end); 
    }
    
//조회수 증가 처리
    @Override
    public void increaseViewcnt(int bno, HttpSession session) 
            throws Exception {
        long update_time=0;
        if(session.getAttribute("update_time_"+bno)!=null) {
            //최근에 조회수를 올린 시간
            update_time=
                    (long)session.getAttribute("update_time_"+bno);
        }
        long current_time=System.currentTimeMillis();
        //일정 시간이 경과한 후 조회수 증가 처리
        if(current_time - update_time > 5*1000) {
            //조회수 증가 처리
            boardDao.increateViewcnt(bno);
            //조회수를 올린 시간 저장
            session.setAttribute("update_time_"+bno, current_time);
        }
    }
 
    @Override
    public int countArticle(
            String search_option, String keyword) throws Exception {
        return boardDao.countArticle(search_option,keyword); 
    }
cs



BoardDAOImpl.java

1
2
3
4
5
6
7
8
9
//첨부파일 정보 수정
    @Override
    public void updateAttach(String fullName, int bno) {
        Map<String,Object> map=new HashMap<>(); //값을 여러개 담을때는 haspmap를 사용한다.
        map.put("fullName", fullName); //첨부파일 이름
        map.put("bno", bno); //게시물 번호
        sqlSession.insert("board.updateAttach"map); //updateAttach mapper을 호출
    }
 
cs



boardMapper.xml

1
2
3
4
5
6
7
<!-- 다른 mapper와 중복되지 않도록 네임스페이스 기재 -->
<mapper namespace="board">
<!-- 새로운 첨부파일 추가 -->    
    <insert id="updateAttach">
//attach테이블에 입력받은 파일이름과 게시글 번호를 삽입한다
        insert into attach (fullName, bno) values
        ( #{fullName}, #{bno} )
    </insert>
cs



BoardDAOImpl.java

1
2
3
4
5
    //레코드 수정    
    @Override
    public void update(BoardDTO dto) throws Exception {
        sqlSession.update("board.update"dto); 
    }
cs



boardMapper.xml                                                                                                                                                                            

1
2
3
4
5
6
<mapper namespace="board">
<!-- 게시물 내용 수정 -->
    <update id="update">
//게시글의 내용 수정, 게시글 번호가 맞으면 제목과 내용을 입력한 대로 수정해서 갱신함
        update board
        set title=#{title}, content=#{content}
        where bno=#{bno}
    </update>
cs



view.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
listAttach();
 
//첨부파일 리스트를 출력하는 함수
function listAttach(){
    $.ajax({
        type: "post",
        url: "${path}/board/getAttach/${dto.bno}",
        success: function(list){
            // list : json
            //console.log(list);
            $(list).each(function(){
                var fileInfo=getFileInfo(this);
                //console.log(fileInfo);
                var html="<div><a href='"+fileInfo.getLink+"'>"
                    +fileInfo.fileName+"</a>&nbsp;&nbsp;";
                <c:if test="${sessionScope.userid == dto.writer}">    
                    html+="<a href='#' class='file_del' data-src='"
                        +this+"'>[삭제]</a></div>";
                </c:if>
                $("#uploadedList").append(html);
            });
        }
    });
}
cs



BoardController.java 중 일부

1
2
3
4
5
6
7
8
9
    
    //첨부파일 목록을 리턴
    //ArrayList를 json 배열로 변환하여 리턴
    //view에서 넘긴 bon를 경로값 (url에 포함된 변수)로 받아서 맵핑한다.
    @RequestMapping("getAttach/{bno}")
    @ResponseBody //view가 아닌 데이터 자체를 리턴할 때 사용하는 어노테이션
//(즉, 화면이 바뀌는게 아니라 데이터가 넘어간다는 의미.. 리턴한 값)
    public List<String> getAttach(@PathVariable("bno") int bno){
        return boardService.getAttach(bno);
    }


cs



BoardServiceImpl.java 중 일부

1
2
3
4
    @Override
    public List<String> getAttach(int bno) {
        return boardDao.getAttach(bno);  
    }
cs



BoardDAOImpl.java 중 일부

1
2
3
4
5
    //첨부파일 리스트
    @Override
    public List<String> getAttach(int bno) {
        return sqlSession.selectList("board.getAttach", bno); 
    }
cs



boardMapper.xml 중 일부

1
2
3
4
5
6
7
8
<!-- 다른 mapper와 중복되지 않도록 네임스페이스 기재 -->    
<mapper namespace="board">

<!-- 첨부파일 목록 -->
    <select id="getAttach"  resultType="String"> //결과타입은 필드가 1개이므로 String이다.
        select fullName //attach 테이블에서 첨부파일이름을 검색 (단, 글번호가 내가 선택한 글번호여야됨)
//그리고 날짜의 내림차순으로 정렬시킨다.
        from attach
        where bno=#{bno}
        order by regdate desc    
    </select>
 
cs



여기서 검색한 결과값이 컨트롤러로 넘어간다.




============================첨부 파일 삭제=============================================



view.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
//첨부파일 리스트를 출력하는 함수
function listAttach(){
    $.ajax({
        type: "post",
        url: "${path}/board/getAttach/${dto.bno}"
        //getAttach(파일얻을때) 게시글 번호를 보냄
        //컨트롤러로 이동
        //위의 구문이 처리가 정상적으로 처리되었을때 실행되는 구문 (success)
        //list는 배열
BoardController.java
1
2
3
4
5
6
7
8
    //첨부파일 목록을 리턴
    //ArrayList를 json 배열로 변환하여 리턴
    //view에서 넘긴 bon를 경로값 (url에 포함된 변수)로 받아서 맵핑한다.
    @RequestMapping("getAttach/{bno}")
    @ResponseBody // view가 아닌 데이터 자체를 리턴 
    public List<String> getAttach(@PathVariable int bno){
        return boardService.getAttach(bno);
    }
cs


BoardServiceImpl.java

1
2
3
4
    @Override
    public List<String> getAttach(int bno) {
        return boardDao.getAttach(bno);  
    }
cs



BoardDAOImpl.java

1
2
3
4
5
//첨부파일 리스트
    @Override
    public List<String> getAttach(int bno) {
        return sqlSession.selectList("board.getAttach", bno); 
    }
cs



boardMapper.xml

1
2
3
4
5
6
7
8
9
10
<!-- 다른 mapper와 중복되지 않도록 네임스페이스 기재 -->
<mapper namespace="board">
 
<!-- 첨부파일 목록 -->
    <select id="getAttach"     resultType="String">
//attach테이블로부터 파일이름을 검색, (내가 원하는 글번호로), 작성날짜의 내림차순으로 검색
        select fullName 
        from attach
        where bno=#{bno}
        order by regdate desc    
    </select>
cs
        


success: function(list){
            // list : json
            //console.log(list);
            $(list).each(function(){
                //list 변수 각각에 대하여
                
                //현재 파일의 파일 정보
                var fileInfo=getFileInfo(this);
                //console.log(fileInfo);
                //파일정보를 보는 하이퍼링크를 만듦 (div에 하이퍼링크를 만듦)
                var html="<div><a href='"+fileInfo.getLink+"'>"
                    +fileInfo.fileName+"</a>&nbsp;&nbsp;";
                    
                    
                    
                    //------------파일 삭제-------------
                    //세션에 담긴 userid와 dto에 담긴 작성자가 같으면
                    //담아놓은 파일을 삭제하기 위해서 링크를 건다.
                <c:if test="${sessionScope.userid == dto.writer}">    
                    html+="<a href='#' class='file_del' data-src='"
                        +this+"'>[삭제]</a></div>";
                </c:if>
                //추가
                $("#uploadedList").append(html);
            });
        }
    });
}
cs



view.jsp (위쪽의 #uploadedList)와 연결되는 코드)

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
//첨부파일 삭제
    //id가 uploadedList인 태그의 class가 file_del인 태그 클릭
    $("#uploadedList").on("click",".file_del",function(e){
        var that=$(this); //클릭한 태그
//data: {fileName: $(this).attr("data-src") },        
        $.ajax({
            type: "post",
            url: "${path}/upload/deleteFile",

AjaxUploadController.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
@ResponseBody //뷰가 아닌 데이터를 리턴
    @RequestMapping(value="/upload/deleteFile"
        ,method=RequestMethod.POST)
    public ResponseEntity<String> deleteFile(String fileName){
        logger.info("fileName:"+fileName); 
        
        //fileName에는 이미지 파일의 경우 썸네일 파일 이름이 넘어옴
        String formatName=fileName.substring(
                fileName.lastIndexOf(".")+1); //확장자 검사
        
        
        MediaType mType=MediaUtils.getMediaType(formatName);
        if(mType != null) { //이미지 파일이면 원본이미지 삭제
            
            //파일이름의 앞부분과 확장자명을 분리하기 위한 코드
            String front=fileName.substring(012);
            String end=fileName.substring(14);
            
//         File.separatorChar : 유닉스 / 윈도우즈\    
            new File(uploadPath+(front+end).replace(
                    '/',File.separatorChar)).delete();  //썸네일 삭제
        }
        
        //원본 파일 삭제(이미지이면 썸네일 삭제)
        new File(uploadPath+fileName.replace(
                '/',File.separatorChar)).delete(); //파일 삭제
 
        //레코드 삭제
        boardService.deleteFile(fileName);


BoardService.java

1
2
3
4
5
//첨부파일 레코드 삭제
    @Override
    public void deleteFile(String fullName) {
        boardDao.deleteFile(fullName); 
    }
cs



BoardDAOImpl.java

1
2
3
4
5
//첨부파일 레코드 삭제    
    @Override
    public void deleteFile(String fullName) {
        sqlSession.delete("board.deleteAttach", fullName); 
    }
cs



boardMapper.xml

1
2
3
4
5
<!-- 첨부파일 레코드 삭제 -->
    <delete id="deleteAttach">
        delete from attach
        where fullName=#{fullName}
    </delete>
cs




        return new ResponseEntity<String>("deleted"
                ,HttpStatus.OK);
        //잘 삭제가 되었으면 deleted가 view로 넘어가고 상태메시지200을 리턴시킨다.
    }
}
cs




            
data: "fileName="+    $(this).attr("data-src"),        
            dataType: "text",
            
            //컨트롤러에서 삭제가 성공하면 결과값이 result로 넘어오고
            //result의 값이 deleted와 같으면 화면에서 div 태그를 제거한다.
            
            success: function(result){
                if(result=="deleted"){
//컨트롤러에서 넘어온 리턴값이 deleted면 첨부파일이 정상적으로 삭제되었다는 뜻이므로 밑의 구문을 생성
                    
                    //화면에서 태그 제거
                    
                    that.parent("div").remove();  
                    //that(this를 의미)의 클릭한 태그의 parent의 div를 삭제
                    //div태그를 삭제해야 파일에 관한 링크와 정보들이 삭제된다.
                }
            }
        });
    });
cs



첨부파일이 올라간 상태에서 글을 쓰고 확인을 누르면 mapper에서 id가 addAttach인 쿼리를 호출


파일업로드를 하게되면 트랜잭션 처리를 해야 된다.


왜냐하면 게시글이 올라가고, 파일도 등록되어야 하는데 (board 테이블에도 insert되어야 하고, attach테이블에도 insert되어야 한다)


그렇게 되어야 문제가 발생되지 않기 때문에, 둘 중에 하나만 된다면 롤백시켜야 한다.




===게시글을 작성시, 파일이 첨부되어야 하기 때문에 게시물 쓰기 코드에 트랜잭션을 처리하는 코드를 추가=====================



write.jsp 중 일부

1
2
3
<h2>글쓰기</h2>
<form id="form1" name="form1" method="post"
action="${path}/board/insert.do">

BoardController.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// write.jsp에서 입력한 내용들이 BoardDTO에 저장됨    
    @RequestMapping("insert.do")
    public String insert(@ModelAttribute BoardDTO dto
            , HttpSession session) //세션은 아이디를 확인하기위해서 필요하므로 세션을 가져온다.
        throws Exception {
        
        // 로그인한 사용자의 아이디
        String writer=(String)session.getAttribute("userid");
        dto.setWriter(writer); //로그인한 아이디를 dto에 저장
 
        //레코드 저장
        boardService.create(dto); //서비스와 dao를 통해서 레코드에 추가가된다.
        
        //게시물 목록으로 이동
        return "redirect:/board/list.do";
    }
cs



BoardService.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
    // 1.글쓰기 - 게시물 번호 생성
    
    // 2.첨부파일 등록-게시물 번호 사용
    
    @Transactional //게시물 작성과 파일업로드가 둘다 완료가 된 상태에서만 글을 
                   //써야하기 때문에 트랜잭션 처리를 해주어야 한다.
    @Override
    public void create(BoardDTO dto) throws Exception {
        //board 테이블에 레코드 추가
        boardDao.create(dto); 
        //attach 테이블에 레코드 추가
        String[] files=dto.getFiles(); //첨부파일 이름 배열
        if(files==nullreturn;  //첨부파일이 없으면 skip
        for(String name : files) {
            boardDao.addAttach(name);  //attach 테이블에 insert
            //아직 글번호가 확정되지 않은 상태이기 때문에 (글번호는 작성을 해야 생기기때문) 글번호를 넣는
            //파일업로드는 게시글이 작성이 되지 않으면 업로드가 되지 않게 해야 에러가 발생되지 않는다.
        }
    }
cs



boardMapper.xml

1
2
3
4
5
    <!-- 첨부파일 정보 저장 -->    
    <insert id="addAttach">
//attach테이블에 파일이름 (입력받은 파일이름) 과, 게시글번호(게시판 테이블에 추가된 번호-방금추가된것)를 추가한다,
        insert into attach (fullName, bno) values
        ( #{fullName}, seq_board.currval ) //board.currval은 board의 시퀀스의 최종발급된 번호..
    </insert>
cs


cs



view.jsp에 삭제버튼을 추가하는 코드 추가

1
2
3
4
5
6
$("#btnDelete").click(function(){
    if(confirm("삭제하시겠습니까?")){
        document.form1.action = "${path}/board/delete.do";
        document.form1.submit();

BoardController.java

1
2
3
4
5
    @RequestMapping("delete.do")
    public String delete(int bno) throws Exception {
        boardService.delete(bno); //삭제 처리
        return "redirect:/board/list.do"; //목록으로 이동
    }
cs



BoardServiceImpl.java

1
2
3
4
5
6
7
8
9
10
11
@Transactional 
    //게시글 작성과 마찬가지로 게시글이 삭제될때 첨부파일도 같이 삭제되어야 하기 때문에 트랜잭션 처리를 해준다.
    @Override
    public void delete(int bno) throws Exception {
        //reply 레코드 삭제
        //attach 레코드 삭제
        //첨부파일 삭제
        //board 레코드 삭제
        boardDao.delete(bno); 
    }
 
cs



BoardDAOImpl.java

1
2
3
4
    @Override
    public void delete(int bno) throws Exception {
        sqlSession.delete("board.deleteArticle", bno); //mapper로 게시글 번호를 넘긴다. 
    }
cs



boardMapper.xml

1
2
3
4
<delete id="deleteArticle">
  delete from board where bno=#{bno} 
     </delete>
cs


    }
});
cs


728x90
반응형
:

게시판 만들기 (댓글 쓰기 / 댓글 목록/ 댓글 갯수)

Back-End/Spring 2019. 7. 4. 14:18
728x90
반응형

게시판 만들기 (댓글 쓰기 / 댓글 쓰기 / 댓글 갯수)

 

 

데이터베이스에서 중복될 위험을 방지하기위해 reply 테이블 및 관련 제약조건을 삭제

1
drop table reply cascade constraints;
cs

 

 

댓글 관련 자료를 저장할 reply 테이블을 생성

1
2
3
4
5
6
7
8
create table reply (
rno number not null primary key, //댓글의 고유번호, null값이 들어갈 수 없고, 기본키로 설정함
bno number default 0, //게시글(원글)의 번호, 기본값을 0으로 설정
replytext varchar2(1000not null, //댓글 내용의 글자수를 설정하고, null값이 들어가지 못하게함
replyer varchar2(50not null, //댓글 작성자 아이디의 글자수를 설정하고, null값이 들어가지 못하게함
regdate date default sysdate, //댓글 작성 날짜의 기본값을 현재 시간으로 설정함
updatedate date default sysdate //댓글 수정 날짜의 기본값을 현재 시간으로 설정함
);
cs

 

 

다른테이블의 기본키를 참조할 외래키를 설정 (제약조건을 설정) - 원글과 꼬이는 것을 방지하기 위해서

(댓글과 원글이 꼬이면 안되기 때문에.. 예를 들면 기존에 게시글이 삭제되면 그 게시글에 달려있는 댓글도 같이 삭제되어야 한다.)

1
2
alter table reply add constraint fk_board //reply테이블의 bno속성을 board테이블의 기본키인 (bno)를 참조하는 외래키로 설정함
foreign key(bno) references board(bno); //또한 board테이블의 (bno)의 값이 변경되면 연쇄적으로 reply테이블의 (bno)의 값도 같이 변경된다.
cs

 

 

댓글 번호 관리를 위한 시퀀스를 설정하기 위해 설정

1
2
3
4
drop sequence reply_seq; //중복될수도 있으니 시퀀스를 삭제.
create sequence reply_seq //시작값을 1로하고 1씩 증가하는 reply_seq 시퀀스를 생성함.
start with 1
increment by 1;
cs

 

 

작업후에 결과를 반영하기 위해 commit 하기

1
commit;
cs
 
 
view.jsp 중 일부
"댓글쓰기" 버튼을 누르면 서버에 저장이 되고 저장된 목록을 출력할 예정
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<!-- 댓글 작성 -->
<!-- 너비와 정렬방식 설정 -->
<div style="width:700px; text-align:center;">
 
<!-- 세션에 저장되어있는 userid가 null이 아닐때 -->
<!-- 그러니까 로그인을 한 상태이어야만 댓글을 작성 할 수 있다.-->
     <c:if test="${sessionScope.userid != null }">
     
     
         <textarea rows="5" cols="80" id="replytext"
             placeholder="댓글을 작성하세요"></textarea>
         <br>
         <!-- 댓글쓰기 버튼을 누르면 id값인 btnReply값이 넘어가서 -->
         <!-- 위쪽에 있는 스크립트 구문이 실행되고 -->
         <!-- 내가 댓글을 작성한 값이 스크립트문을 거쳐서 컨트롤러로 맵핑되게 된다. -->
         <button type="button" id="btnReply">댓글쓰기</button>
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//댓글 쓰기 (버튼을 눌러서 id값이 넘어와 실행되는 자바스크립트 구문)
    $("#btnReply").click(function(){
        var replytext=$("#replytext").val(); //댓글 내용
        var bno="${dto.bno}"//게시물 번호
        var param="replytext": replytext, "bno": bno};
        //var param="replytext="+replytext+"&bno="+bno;
        $.ajax({
            type: "post", //데이터를 보낼 방식
            url: "${path}/reply/insert.do", //데이터를 보낼 url
            data: param, //보낼 데이터
 
            success: function(){ //데이터를 보내는것이 성공했을시 출력되는 메시지
                alert("댓글이 등록되었습니다.");
                listReply2(); //댓글 목록 출력
            }
        });
    });
cs
     
</c:if>
</div>
<!-- 댓글 목록 -->
<!-- 댓글이 등록이 되면 listReply에 댓글이 쌓이게 된다 -->
<div id="listReply"></div>
 
1
2
3
4
5
6
7
8
9
10
11
//댓글 목록 출력 함수
function listReply(){
    $.ajax({
        type: "get", //get방식으로 자료를 전달한다
        url: "${path}/reply/list.do?bno=${dto.bno}", //컨트롤러에 있는 list.do로 맵핑하고 게시판 번호도 같이 보낸다.
        success: function(result){ //자료를 보내는것이 성 공했을때 출력되는 메시지
            //result : responseText 응답텍스트(html)
            $("#listReply").html(result);
        }
    });
}
cs
 
 
 
</body>
</html>
cs
 

 

 

댓글 관련 자료를 저장할 DTO를 생성

 

 

ReplyDTO.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
package com.example.spring02.model.board.dto;
 
import java.util.Date;
 
public class ReplyDTO {
 
    private int rno; //댓글 번호
    private int bno; //게시물 번호
    private String replytext; //댓글 내용
    private String replyer; //댓글 작성자 id
    private String name; //댓글 작성자 이름
    private Date regdate; //java.util.Date, 작성일자
    private Date updatedate; //수정일자
    private String secret_reply; //비밀댓글 여부
    private String writer; //member 테이블의 id
 
    //getter,setter,toString()
 
    public int getRno() {
        return rno;
    }
    public void setRno(int rno) {
        this.rno = rno;
    }
    public int getBno() {
        return bno;
    }
    public void setBno(int bno) {
        this.bno = bno;
    }
    public String getReplytext() {
        return replytext;
    }
    public void setReplytext(String replytext) {
        this.replytext = replytext;
    }
    public String getReplyer() {
        return replyer;
    }
    public void setReplyer(String replyer) {
        this.replyer = replyer;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Date getRegdate() {
        return regdate;
    }
    public void setRegdate(Date regdate) {
        this.regdate = regdate;
    }
    public Date getUpdatedate() {
        return updatedate;
    }
    public void setUpdatedate(Date updatedate) {
        this.updatedate = updatedate;
    }
    public String getSecret_reply() {
        return secret_reply;
    }
    public void setSecret_reply(String secret_reply) {
        this.secret_reply = secret_reply;
    }
    public String getWriter() {
        return writer;
    }
    public void setWriter(String writer) {
        this.writer = writer;
    }
    @Override
    public String toString() {
        return "ReplyDTO [rno=" + rno + ", bno=" + bno + ", replytext=" + replytext + ", replyer=" + replyer + ", name="
                + name + ", regdate=" + regdate + ", updatedate=" + updatedate + ", secret_reply=" + secret_reply + ", writer="
                + writer + "]";
    }
    
}
 
cs

 

 

 

ReplyController.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
package com.example.spring02.controller.board;
 
import java.util.List;
 
import javax.inject.Inject;
import javax.servlet.http.HttpSession;
 
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView;
 
import com.example.spring02.model.board.dto.ReplyDTO;
import com.example.spring02.service.board.ReplyService;
 
// @ResponseBody를 붙이지 않아도 뷰가 아닌 데이터 리턴 가능
@RestController // spring 4.0부터 사용 가능
@RequestMapping("reply/*"//공통적인 url pattern
public class ReplyController {
 
    @Inject        //서비스를 호출하기위해서 의존성을 주입
    ReplyService replyService;
    
    //댓글리스트를 호출할때 맵핑되는 메소드
    @RequestMapping("list.do")
    public ModelAndView list(int bno, ModelAndView mav) {
        List<ReplyDTO> list=replyService.list(bno); //댓글 목록
        mav.setViewName("board/reply_list"); //뷰의 이름
        mav.addObject("list", list); //뷰에 전달할 데이터 저장
        return mav; //뷰로 이동
    }
    
    //댓글 목록을 ArrayList로 리턴
    @RequestMapping("list_json.do")
    public List<ReplyDTO> list_json(int bno){
        return replyService.list(bno);
    }
    
    @RequestMapping("insert.do"//세부적인 url pattern
    public void insert(ReplyDTO dto, HttpSession session) {
        
        //댓글 작성자 아이디
//현재 접속중인 사용자 아이디
        String userid=(String)session.getAttribute("userid");
        dto.setReplyer(userid);
        
        //댓글이 테이블에 저장됨
        replyService.create(dto);
        //jsp 페이지로 가거나 데이터를 리턴하지 않음
    }
}
cs

 

 

 

ReplyService.java 작성

1
2
3
4
5
6
7
8
9
10
11
12
13
package com.example.spring02.service.board;
 
import java.util.List;
 
import com.example.spring02.model.board.dto.ReplyDTO;
 
public interface ReplyService {
 
    public List<ReplyDTO> list(int bno); //댓글 리스트
    public int count(int bno);            //댓글 수
    public void create(ReplyDTO dto);    //댓글 작성
    
}
cs

 

 

 

ReplyServiceImpl.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
package com.example.spring02.service.board;
 
import java.util.List;
 
import javax.inject.Inject;
 
import org.springframework.stereotype.Service;
 
import com.example.spring02.model.board.dao.ReplyDAO;
import com.example.spring02.model.board.dto.ReplyDTO;
 
@Service //service bean
public class ReplyServiceImpl implements ReplyService {
    
    
    @Inject
    ReplyDAO replyDao;    //dao를 호출하기위해서 의존성을 주입
 
    
    //댓글 목록
    @Override
    public List<ReplyDTO> list(int bno) {
        return replyDao.list(bno);
    }
    
    
    @Override
    public int count(int bno) {
        return 0;
    }
    
    
    //댓글 쓰기    
    @Override
    public void create(ReplyDTO dto) {
        replyDao.create(dto);
    }
    
}
cs

 

 

 

ReplyDAO.java

1
2
3
4
5
6
7
8
9
10
11
12
package com.example.spring02.model.board.dao;
 
import java.util.List;
 
import com.example.spring02.model.board.dto.ReplyDTO;
 
public interface ReplyDAO {
    public List<ReplyDTO> list(int bno); //댓글 목록
    public int count(int bno);           //댓글 수
    public void create(ReplyDTO dto);    //댓글 작성
}
 
cs

 

 

 

ReplyDAOImpl.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
package com.example.spring02.model.board.dao;
 
import java.util.List;
 
import javax.inject.Inject;
 
import org.apache.ibatis.session.SqlSession;
import org.springframework.stereotype.Repository;
 
import com.example.spring02.model.board.dto.ReplyDTO;
@Repository //dao bean
public class ReplyDAOImpl implements ReplyDAO {
    
    @Inject //의존관계 주입
    SqlSession sqlSession;
 
    //댓글 목록
    @Override
    public List<ReplyDTO> list(int bno) {
        return sqlSession.selectList("reply.listReply", bno);
    }
    
    @Override
    public int count(int bno) {
        return 0;
    }
    
    //댓글 추가    
    @Override
    public void create(ReplyDTO dto) {
        sqlSession.insert("reply.insertReply", dto); 
    }
}
cs

 

 

 

replyMapper.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?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="reply">
    <insert id="insertReply">
    <!-- 댓글을 추가 (댓글번호, 글번호, 댓글내용, 댓글작성자를 추가 댓글번호는 시퀀스로 추가 -->
        insert into reply (rno,bno,replytext,replyer) values
        ( reply_seq.nextval, #{bno}, #{replytext}, #{replyer} )
    </insert>
    
    <select id="listReply"
resultType="com.example.spring02.model.board.dto.ReplyDTO">
<!-- 댓글의 작성자와 회원 아이디가 같고, 글번호가 같을 경우에 댓글 리스트를 검색 (내림차순으로)-->
        select rno,bno,replyer,regdate,updatedate,name,replytext 
        from reply r, member m
        where r.replyer=m.userid and bno=#{bno}
        order by rno    
    </select>
</mapper>
cs

 

 

view.jsp

1
2
3
4
5
6
7
8
9
10
11
12
//댓글 목록 출력 함수
function listReply(num){
    $.ajax({
        type: "post"//post방식으로 자료를 
        url: "${path}/reply/list.do?bno=${dto.bno}&curPage"//컨트롤러에 있는 list.do로 맵핑하고 현재페이지와 게시판 번호도 같이 보낸다.
        success: function(result){ //자료를 보내는것이 성공했을때 출력되는 메시지
            //result : responseText 응답텍스트(html)
            console.log(result);
            $("#listReply").html(result);
        }
    });
}
cs

 

 

댓글 갯수 확인 쿼리

 

1
2
3
4
5
select bno, title, writer, name, regdate, viewcnt,
    (select count(*from reply where bno = b.bno)cnt //게시글 번호, 제목, 작성자, 이름, 시간, 조회수, 그리고 댓글의 수를 검색 (cnt라는 약자로함)
from board b, member m //테이블 2개를 조인.
where b.writer = m.userid //board의 writer과 member의 userid가 같은것만
order by bno desc; //조건에 맞는 자료를 게시글 번호의 내림차순으로 검색
cs

 

 

이 쿼리를 사용하기 위해 boardMapper.xml에 추가함

 

boardMapper.xml (listAll에 있는 쿼리문을 수정. 댓글의 개수를 제목옆에 출력할 수 있도록)

1
2
3
4
5
6
7
8
9
10
<select id="listAll"
    resultType="com.example.spring02.model.board.dto.BoardDTO">
    <!-- 결과는 boardDTO타입이 된 -->
        <include refid="paging_header" /
        <!-- ref는 다른테이블을 의미한다. -->
        <!-- 번호, 제목, 작성자, 이름, 날짜, 조회수 , 그리고 댓글의 갯수를 검색 -->
        <!-- board 테이블과 member 테이블로 부터 검색 -->
            select bno,title,writer,name,regdate,viewcnt,show
   ,(select count(*) from reply where bno=b.bno) cnt                    
             from board b, member m
 
                Colored by Color Scripter
cs

 

 

list.jsp에 방금 사용한 쿼리의 댓글 개수 (cnt값) 을 출력하기 위해 값을 받아온다.

1
2
3
<c:if test="${row.cnt > 0}"> //댓글의 개수가 0보다 크면 실행되는 구문
    <span style="color:red;">( ${row.cnt} )</span> //댓글의 개수를 출력하고 색깔을 빨간색으로 한다.
</c:if>   
cs

아래 책은 제가 공부할때 활용했던 책으로 추천드리는 책이니 한번씩 읽어보시는것을 추천드립니다!! ㅎㅎ

토비의 스프링 3.1 세트:스프링의 이해와 원리 + 스프링의 기술과, 에이콘출판

이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.

 

728x90
반응형
:

Spring Editor (CKEditor, SummerNote) 사용

Back-End/Spring 2019. 7. 2. 11:29
728x90
반응형

Smart Editor

 

WYSIWYG Editor (위지윅 에디터, whar you see is what you ger)

 

- 사용자가 현재 화면에서 보고 있는 내용과 동일한 html code를 생성하는 에디터

 

- 네이버, 다음 에디터, CKEditor, SummerNote 등

 

 



  CKEditor과 SummerNote의 차이점


  CKEditor : 이미지 파일은 디렉토리에 저장, 테이블에는 링크만 저장


  Summernote : 이미지를 테이블에 저장 (이미지를 테이블에 저장하면 DB가 과부하가 걸릴 수 있다.)

 

 

가. CKEditor

 

- http://ckeditor.com

 

- 자바스크립트 기반 위지윅 웹에디터, 쉬운 이식, 웹사이트 구축언어가 asp든, php든 관계없이 도입하기가 용이하다.

 

- 현재 CKEditor5 버전이 최신 버전이지만 여기서는 안정화된 버전인 CKEditor 4.11.2 버전으로 실습함

 

- 이미지 업로드를 위해서는 별도의 작업이 필요함 (컨트롤러를 미리 호출하는 등의 작업이 필요..)

 

 

 

-다운로드 방법-

 

1. https://ckeditor.com/ckeditor-4/download/ 접속

 

 

2. Standard Package 다운로드

 

 

 

3. 다운로드 후 압축을 풀고 ckeditor 디렉토리를 views에 붙인다.

 

 

 

 

 

- ckeditor 실습 예제 -

 

  
  view 하위의 디렉토리들은 기본적으로 selvlet으로 인식이 된다.


  그렇기 때문에 리소스로 등록을 하지 않으면 링크가 되지 않고 404에러가 발생을 하게 된다.


  그렇기 때문에 servlet-context.xml에 리소스 매핑을 해주어야 한다.

 

1. servlet-context.xml에 리소스 매핑을 추가

1
<resources location="/WEB-INF/views/ckeditor/" mapping="/ckeditor/**"></resources>
cs

 

 

2. ckeditor.js 참조 (ckeditor을 붙이고 싶은 파일로 이동해서 태그를 넣으면 된다)

1
<script src = "${path}/ckeditor/ckeditor.js"></script>
cs

 

 

3. ckeditor를 적용할 태그에 작성

(WEB-INF/views/shop/product_write.jsp 와 product_edit.jsp 에 적용해보기)

 

1
2
3
4
5
6
7
8
9
10
11
12
13
<div style = "width:800px;">
내용
<textarea id = "description" name = "description" rows = "5" cols = "80"
placeholder = "상품설명을 입력하세요"></textarea> //이런 textarea가 있을때 주로 스마트에디터를 많이 사용
<!--textarea를 스마트에디터로 변경함--!>
<script>
//CKEDITOR.replace("description"); //태그의 id
//이미지 업로드를 할 경우
CKEDITOR.replace("description",{
 
//CKEDITOR.replace와 id("description")를 잘 적어주면 그 태그가 smart editor 스타일로 바뀌게 된다.
 
    filebrowserUploadUrl : "${path}/imageUpload.do"
 
//파일을 업로드 해야하기 때문에 filebrowserUploadUrl을 사용하고, 서버쪽에 코드를 완성해주어야 한다.
 
});
</script>
</div>    
cs

 

 

4. product_write.jsp 에 ckeditor을 적용하기 위한 코드를 추가

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
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
    <!-- views/shop/product_write.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" %>
 
<!-- ckeditor 사용을 위해 js 파일 연결 -->
<script src="${path}/ckeditor/ckeditor.js"></script>
 
</head>
<body>
<%@ include file="../include/admin_menu.jsp" %>
 
============중간생략==========================
 
<tr>
        <td>상품설명</td>
        <td><textarea rows="5" cols="60" 
            name="description" id="description"></textarea>
 
<script>
//id가 description인 태그에 ckeditor를 적용시킴
//이미지 업로드 안됨
CKEDITOR.replace("description",{
    filebrowserUploadUrl : "${path}/imageUpload.do"
}); //이미지 업로드 기능을 추가하기위한 코드
</script>
            
        </td>
    </tr>
    <tr>
        <td>상품이미지</td>
        <td>
            <input type="file" name="file1" id="file1"
        </td>
    </tr>
cs

 

 

 

5. ImageUploadController.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
package com.example.spring02.controller.upload;
 
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
 
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.multipart.MultipartFile;
 
@Controller // 컨트롤러 어노테이션
public class ImageUploadController {
 
    // 컨트롤러클래스의 로그를 출력
    private static final Logger logger = LoggerFactory.getLogger(ImageUploadController.class);
 
    // 이미지 업로드
    // product_edit페이지에서 맵핑되는 메소드
    @RequestMapping("imageUpload.do")
 
    // 이미지를 저장하고, 불러오고, 업로드하기위해 매개변수를 선언
    public void imageUpload(HttpServletRequest request, HttpServletResponse response, @RequestParam MultipartFile upload)
//MultipartFile 타입은 ckedit에서 upload란 이름으로 저장하게 된다
            throws Exception {
 
        // 한글깨짐을 방지하기위해 문자셋 설정
        response.setCharacterEncoding("utf-8");
 
        // 마찬가지로 파라미터로 전달되는 response 객체의 한글 설정
        response.setContentType("text/html; charset=utf-8");
 
        // 업로드한 파일 이름
        String fileName = upload.getOriginalFilename();
 
        // 파일을 바이트 배열로 변환
        byte[] bytes = upload.getBytes();
 
        // 이미지를 업로드할 디렉토리(배포 디렉토리로 설정)
        String uploadPath = "D:\\work\\.metadata\\.plugins\\org.eclipse.wst.server.core\\tmp1\\wtpwebapps\\spring02\\WEB-INF\\views\\images\\";
 
  프로젝트는 개발 디렉토리에 저장이 되는데 이미지를 업로드할 디렉토리를 개발 디렉토리로 설정하면 일일이 새로고침을 해주어야되서
 
불편하기 때문에 이미지를 업로드할 디렉토리를 배포 디렉토리로 설정한다.
        
OutputStream out = new FileOutputStream(new File(uploadPath + fileName));
 
        // 서버로 업로드
        // write메소드의 매개값으로 파일의 총 바이트를 매개값으로 준다.
        // 지정된 바이트를 출력 스트립에 쓴다 (출력하기 위해서)
        out.write(bytes);
 
        // 클라이언트에 결과 표시
        String callback = request.getParameter("CKEditorFuncNum");
 
        // 서버=>클라이언트로 텍스트 전송(자바스크립트 실행)
        PrintWriter printWriter = response.getWriter();
        String fileUrl = request.getContextPath() + "/images/" + fileName;
        printWriter.println("<script>window.parent.CKEDITOR.tools.callFunction(" + callback + ",'" + fileUrl
                + "','이미지가 업로드되었습니다.')" + "</script>");
        printWriter.flush();
    }
}
cs

 

 

만약에 에러가 발생할 경우

 

ckeditor / config.js 파일을 열고 마지막 라인에 추가

 

 config.filebrowserUploadMethod = 'form';

 

 

 

ckeditor 적용 화면

 

 

 

나. SummerNote

 

- http://summernote.org (우리나라 개발자들이 만듦)

 

- 이미지를 텍스트 형식으로 저장함

 

- 적용 예시

 

 

1. http://summernote.org 접속해서 SummerNote 다운로드

 

 

 

 

2. 압축을 풀고 dist 디렉토리를 views에 붙이고 이름을 summernote로 변경한다.

 

 

 

3. servlet-context.xml에 리소스 매핑 추가

(location이 실제 경로이고, mapping가 url 상의 경로를 의미한다)

1
<resources location="/WEB-INF/views/summernote/" mapping="/summernote/**"></resources>
cs
 
4. product_write.jsp (상품정보 쓰기 페이지)에 summernote를 적용
 
 
4-1 적용시킬 코드를 찾기 위해 summernote 홈페이지로 이동하고,  Getting started를 클릭

 

 
4-2 스크롤바를 밑으로 내려서 Include js/css 안에 있는 코드를 복사한다. (summernote 라이브러리를 사용하기 위한 코드)

 

 
5. product_write.jsp (상품정보 쓰기 페이지)에 summernote를 적용 시키는 코드를 추가
(복사한 코드를 붙여넣기)
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
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
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
    <!-- views/shop/product_write.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" %>
 
<!-- include libraries(jQuery, bootstrap) -->
<!-- summernote홈페이지에서 받은 summernote를 사용하기 위한 코드를 추가 -->
<link href="http://netdna.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.css" rel="stylesheet">
<script src="http://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.js"></script> 
<script src="http://netdna.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.js"></script> 
 
<!-- include summernote css/js -->
<!-- 이 css와 js는 로컬에 있는 것들을 링크시킨 것이다. -->
<link href="http://cdnjs.cloudflare.com/ajax/libs/summernote/0.8.12/summernote.css" rel="stylesheet">
<script src="http://cdnjs.cloudflare.com/ajax/libs/summernote/0.8.12/summernote.js"></script>
 
 
 
<%-- <!-- ckeditor 사용을 위해 js 파일 연결 -->
같은 페이지에 스마트에디터를 동시에 2개를 사용할 수 없으므로 ckeditor은 주석처리 한다.
<script src="${path}/ckeditor/ckeditor.js"></script> --%>
 
</head>
<body>
<%@ include file="../include/admin_menu.jsp" %>
 
<script>
//id가 description인 것을 summernote 방식으로 적용하라는 의미이다.
//높이와 넓이를 설정하지 않으면 화면이 작게 나오기때문에 설정해주어야 한다.
$(function(){
    $("#description").summernote({
        height : 300,
        width : 800
    });
});
 
 
function product_write(){
    // 태그를 name으로 조회할 경우
    //var product_name=document.form1.product_name.value;
    // 태그를 id로 조회할 경우
    var product_name=$("#product_name").val();
    var price=$("#price").val();
    var description=$("#description").val();
    if(product_name==""){ //빈값이면
        alert("상품이름을 입력하세요"); 
        $("#product_name").focus(); //입력포커스 이동
        return//함수 종료, 폼 데이터를 제출하지 않음
    }
    if(price==""){
        alert("가격을 입력하세요");
        $("#price").focus();
        return;
    }
/*     if(description==""){
        alert("상품 설명을 입력하세요");
        $("#description").focus();
        return;
    } */
    //폼 데이터를 받을 주소
    document.form1.action="${path}/shop/product/insert.do";
    //폼 데이터를 서버에 전송
    document.form1.submit();
}
</script>
 
 
<h2>상품 등록</h2>
<form name="form1" method="post"
    enctype="multipart/form-data">
<table>
    <tr>
        <td>상품명</td>
        <td><input name="product_name" id="product_name"></td>
    </tr>
    <tr>
        <td>가격</td>
        <td><input name="price" id="price"></td>
    </tr>
    <tr>
        <td>상품설명</td>
        <td><textarea rows="5" cols="60" 
            name="description" id="description"></textarea>
<script>
//위쪽과 마찬가지로 같은페이지에서 스마트에디터를 동시에 2개를 사용할 수 없으므로 주석처리 한다.
//id가 description인 태그에 ckeditor를 적용시킴
//CKEDITOR.replace("description"); //이미지 업로드 안됨
/* CKEDITOR.replace("description",{
    filebrowserUploadUrl : "${path}/imageUpload.do"
}); */
</script>            
        </td>
    </tr>
    <tr>
        <td>상품이미지</td>
        <td>
            <input type="file" name="file1" id="file1"
        </td>
    </tr>
    <tr>
        <td colspan="2" align="center">
            <input type="button" value="등록" 
                onclick="javascript:product_write()">
            <input type="button" value="목록"
onclick="location.href='${path}/shop/product/list.do'">
        </td>
    </tr>
</table>    
</form>
 
</body>
</html>
cs

 

 

 

summernote 적용 화면

 

 

아래 책은 제가 공부할때 활용했던 책으로 추천드리는 책이니 한번씩 읽어보시는것을 추천드립니다!! ㅎㅎ

토비의 스프링 3.1 세트:스프링의 이해와 원리 + 스프링의 기술과, 에이콘출판

이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받습니다.

728x90
반응형

'Back-End > Spring' 카테고리의 다른 글

게시판 만들기 (게시글 목록)  (0) 2019.07.02
게시판 만들기 (기본구조, 테이블 생성)  (0) 2019.07.02
Spring 이메일 보내기  (1) 2019.07.01
Spring xml bean property 정리  (0) 2019.07.01
jQuery 이벤트 바인딩  (0) 2019.06.30
:

스프링을 사용해서 pdf 생성

Back-End/Spring 2019. 6. 19. 23:21
728x90
반응형

스프링을 사용해서 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

1
2
3
4
5
6
7
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<%@ 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


728x90
반응형
: