'Back-End/Spring'에 해당되는 글 102건

  1. 2019.07.25 스프링 - 네이버 로그인 구현 (네이버 아이디로 로그인)
  2. 2019.07.24 자바스크립트 연동해서 서버로부터 메시지 받아서 팝업 띄우기
  3. 2019.07.13 스프링 시큐리티
  4. 2019.07.12 Spring SQL Server 연동 (실습) 1
  5. 2019.07.10 Spring와 SQL Server 연동 2
  6. 2019.07.10 Spring Boot와 MongoDB 연동 실습 (방명록)
  7. 2019.07.09 Spring Boot와 MongoDB 연동 실습 (한줄메모장)
  8. 2019.07.08 Spring 어노테이션 정리

스프링 - 네이버 로그인 구현 (네이버 아이디로 로그인)

Back-End/Spring 2019. 7. 25. 15:30

1. https://developers.naver.com/docs/login/api/ (네이버 개발 관련 홈페이지) 로 접속하고, 오픈 API이용 신청


ㄱ. 사용 API에 전부다 체크




ㄴ. 서비스 URL (네이버 로그인 버튼이 있는 URL 주소) , Callback URL (로그인 한후 결과페이지 URL 주소)를 적어넣고,

애플리케이션 정보에서 Client ID와 Client Secret 를 메모장에 따로 적어놓기 (이따 사용함)







2. '네이버 아이디로 로그인하기 버튼'이 있는 페이지에서 다음의 코드를 추가 (나같은 경우는 login.jsp)


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<center>
<script type = "text/javascript" src = "https://static.nid.naver.com/js/naverLogin_implicit-1.0.3.js" charset="utf-8"></script>
 
<div id = "naver_id_login"></div>
 
<script type="text/javascript">
 
         var naver_id_login = new naver_id_login("DphfmDygX4WFkf8nghMJ""http://localhost:8090/hansub_project/login_result");    // Client ID, CallBack URL 삽입
                                            // 단 'localhost'가 포함된 CallBack URL
         var state = naver_id_login.getUniqState();
        
         naver_id_login.setButton("white"440);
         naver_id_login.setDomain("http://localhost:8090/hansub_project/login");    //  URL
         naver_id_login.setState(state);
         naver_id_login.setPopup();
         naver_id_login.init_naver_id_login();
 
</script>
</center>
cs


위와 같이 위에서 말한 4가지 정보중, Client ID, 서비스 URL, CallBack URL을 찾아서 삽입한다.


(주의할 점은, '127.0.0.1' 이 아닌, 'localhost' 가 포함된 CallBack URL을 넣는다는 것입니다.)




3. 로그인 후 처리 페이지 (login_result.jsp 페이지)


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<script type="text/javascript">
        var naver_id_login = new naver_id_login("DphfmDygX4WFkf8nghMJ", "http://localhost:8090/hansub_project/login_result"); // 역시 마찬가지로 'localhost'가 포함된 CallBack URL
        
        // 접근 토큰 값 출력
        alert(naver_id_login.oauthParams.access_token);
        
        // 네이버 사용자 프로필 조회
        naver_id_login.get_naver_userprofile("naverSignInCallback()");
        
        // 네이버 사용자 프로필 조회 이후 프로필 정보를 처리할 callback function
        function naverSignInCallback() {
            alert(naver_id_login.getProfileData('email'));
            alert(naver_id_login.getProfileData('nickname'));
            alert(naver_id_login.getProfileData('age'));
        }
    </script>
cs



위와 비슷하게 Client ID, CallBack URL을 찾아 삽입하면 되는데, CallBack URL은 위와 같이 'localhost' 가 포함된 주소를 삽입한다.


주석에 보이는 접근 토큰 (access token)으로 로그인한 회원의 '프로필 조회' 를 비롯한 여러가지 다른 오픈 API를 호출할 수 있다.




4. 컨트롤러는 위의 두가지 페이지로 가게 해주게 설정하면 된다.


1
2
3
4
5
6
7
8
9
10
11
    @RequestMapping(value="login", method=RequestMethod.GET)
    public String loginGET() {
        
        return "user/login";
    }
    
    @RequestMapping(value="loginPostNaver", method=RequestMethod.GET)
    public String loginPOSTNaver(HttpSession session) {
        
        return "user/loginPostNaver";
    }
cs











출처

https://thiago6.tistory.com/44

:

자바스크립트 연동해서 서버로부터 메시지 받아서 팝업 띄우기

Back-End/Spring 2019. 7. 24. 16:45

1. 먼저 header파일에 라이브러리 태그 코드 추가


1
2
3
4
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%>
<%@ taglib prefix="fn" uri="http://java.sun.com/jsp/jstl/functions" %>
 
cs



2. jquery를 사용하기 위해 스크립트를 추가하고, 메시지를 보여줄 수 있는 alert함수를 호출하는 스크립트 코드를 추가


1
2
3
4
5
6
7
8
9
10
<!-- 회원정보에 없는 이메일을 입력할 시에 출력되는 경고창 -->
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script>
    $(function(){
        var responseMessage = "<c:out value="${message}" />";
        if (responseMessage != ""){
            alert(responseMessage)
        }
    })
</script>
cs



3. 서버의 컨트롤러 코드에서 반환할 ModelAndView 객체에 message 라는 이름의 오브젝트를 추가


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
//아이디 찾기 처리
    @RequestMapping("find_id.do")
    public ModelAndView find_id(String e_mail) {
        ModelAndView mav = new ModelAndView();
        MemberDTO dto = new MemberDTO();
        
        dto.setE_mail(e_mail);
        String user_id = memberservice.find_idCheck(dto);
        
        if(user_id != null) {
            mav.setViewName("find_id_result");    
            mav.addObject("user_id", user_id);
        
        }else {
            //아이디 찾기 실패
            mav.setViewName("find_user_id");
            //뷰에 전달할 값
            mav.addObject("message""회원가입된 회원의 이메일이 아닙니다");
 
        }
        
        
        
        return mav;
    }
cs




4. 결과 팝업창 화면



















출처

https://jhlblue.tistory.com/5

:

스프링 시큐리티

Back-End/Spring 2019. 7. 13. 12:28

스프링 시큐리티의 개요


1) 웹 보안의 3요소


- 인증 (Authentication) : 애플리케이션의 작업을 수행할 수 있는 주체 (사용자). 현재 접속중인 사용자가 누구인지 확인하는 과정


- 권한 인가 (Authorization) : 인증된 주체가 애플리케이션의 동작을 수행 할 수 있도록 허락되어 있는지 증명하는 과정.

현재 사용자가 특정 url에 접속할 권한이 있는지 검사하는 과정


- UI 처리 : 권한이 없는 사용자가 접근할 경우의 에러 화면 등을 보여주는 과정



2) 스프링 시큐리티


개발자가 직접 처리하던 보안 처리 과정을 스프링 프레임워크에서 제공하는 스프링 시큐리티를 사용하여 사용권한 관리,


비밀번호 암호화, 회원가입 처리, 로그인, 로그아웃 등의 웹 보안 관련 기능 개발을 쉽게 처리할 수 있음.



-실습소스-


1) 회원 정보 테이블 생성

1
2
3
4
5
6
7
8
create table users(
    userid varchar2(255not null--id
    passwd varchar2(255not null--비밀번호, 암호화 할 예정
    name varchar2(255not null--이름
    enabled number(1default 1--사용가능 여부, 값이 1이면 사용가능 , 0이면 사용할 수 없는 id라는걸 표시하는 속성
    authority varchar2(20default 'ROLE_USER',  --권한설정 속성, ROLE_USER와 admin으로 구성되어 있다. / 일반사용자/관리자
    primary key(userid) --기본키를 id로 설정함
);
cs



스프링 레거시 프로젝트로 작성.


pom.xml에 버전을 일부 수정하고, 오라클 라이브러리를 추가, spring security 라이브러리를 추가한다. 나머지는 샘플 pom.xml에 있는것과 동일


pom.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
    <properties>
        <java-version>1.8</java-version>
        <org.springframework-version>5.1.4.RELEASE</org.springframework-version>
        <org.aspectj-version>1.9.2</org.aspectj-version>
        <org.slf4j-version>1.7.25</org.slf4j-version>
        <spring.security.version>5.1.3.RELEASE</spring.security.version>
    </properties>



      <!-- 오라클 라이브러리 -->
<!--오라클도 상용 라이브러리이기 때문에 maven 저장소에는 오픈소스가 올라가져 있고 버전도 맞지 않는다.
 이 저장소를 추가해서 오라클 라이브러리를 추가 --> <repositories> <repository> <id>codelds</id> <url>https://code.lds.org/nexus/content/groups/main-repo</url> </repository> </repositories>
 
 
============================================================================================
 
 
        <!-- Spring Security -->
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-core</artifactId>
            <version>${spring.security.version}</version>
            <type>jar</type>
            <scope>compile</scope>
        </dependency>
 
 
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-web</artifactId>
            <version>${spring.security.version}</version>
            <type>jar</type>
            <scope>compile</scope>
        </dependency>
 
 
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-config</artifactId>
            <version>${spring.security.version}</version>
            <type>jar</type>
            <scope>compile</scope>
        </dependency>
 
 
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-taglibs</artifactId>
            <version>${spring.security.version}</version>
            <type>jar</type>
            <scope>compile</scope>
        </dependency>

cs




web.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
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
 
    <!-- The definition of the Root Spring Container shared by all Servlets and Filters -->
        
<!-- 스프링 환경 설정 파일 + 스프링 시큐리티 환경 설정 파일 로딩 -->
<context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>
            /WEB-INF/spring/root-context.xml
            /WEB-INF/spring/security/security-context.xml //추가
        </param-value>
    </context-param>
    
 
    <!-- Creates the Spring Container shared by all Servlets and Filters -->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
 
    <!-- Processes application requests -->
    <servlet>
        <servlet-name>appServlet</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>
                /WEB-INF/spring/appServlet/servlet-context.xml
            </param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
 
    <servlet-mapping>
        <servlet-name>appServlet</servlet-name>
        <url-pattern>/</url-pattern>

//"/"라는것은 디폴트 서블릿 서블릿으로 요청이 들어오면 dispatcherservlet로 처리를 하고, dispatcherservlet에서는
// servlet-context를 읽어들여서 맵핑을 처리한다는 의미

    </servlet-mapping>
 

<!-- 스프링 시큐리티에서 사용하는 세션 이벤트 처리 관련 리스터 세션 만료 체크, 동시 로그인 제한 등의 기능 제공 -->
    <listener>
        <listener-class>
org.springframework.security.web.session.HttpSessionEventPublisher</listener-class>
    </listener>
    
    
    <!-- 애플리케이션의 모든 요청을 스프링 시큐리티에서 처리하도록 하는 필터 -->
    <filter>
        <filter-name>springSecurityFilterChain</filter-name>
        <filter-class> org.springframework.web.filter.DelegatingFilterProxy </filter-class>
    </filter>                                <!-- DelegatingFilterProxy서버가 돌아가면서 스프링시큐리티에서 처리를 하게 함 -->
    <filter-mapping>
        <filter-name>springSecurityFilterChain</filter-name>
        <url-pattern>/*</url-pattern>
// "/*" 는 모든 요청이라는 의미이고, 모든 요청시에는 DelegatingFilterProxy라는 스프링 시큐리티필터를 한번 거쳐서
// 가게 되어 있다.

    </filter-mapping>
    
    
    
    <!-- 한글 처리를 위한 인코딩 필터 -->
    <filter>
        <filter-name>encoding</filter-name>
        <filter-class>
org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>encoding</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

    <!-- 세션 타임아웃 설정 -->
    <session-config>
        <session-timeout>20</session-timeout>
    </session-config>
 
</web-app>
cs



servlet-context (서블릿 관련 설정 파일)

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
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/mvc"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:beans="http://www.springframework.org/schema/beans"
    xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:security="http://www.springframework.org/schema/security"
    xsi:schemaLocation="http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security.xsd">
 
    <!-- DispatcherServlet Context: defines this servlet's request-processing 
        infrastructure -->
    <!-- Enables the Spring MVC @Controller programming model -->
    
    <annotation-driven />
    <!-- Handles HTTP GET requests for /resources/** by efficiently serving 
        up static resources in the ${webappRoot}/resources directory -->
        
    <!-- view 밑에 include 디렉토리를 추가할 예정 -->
    <resources mapping="/resources/**" location="/resources/" />
    <resources location="/WEB-INF/views/include/" mapping="/include/**" />
    
    
    <!-- Resolves views selected for rendering by @Controllers to .jsp resources 
        in the /WEB-INF/views directory -->
        
        <!-- view resolver 추가 접두사와 접미사 추가. -->
    <beans:bean
        class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <beans:property name="prefix" value="/WEB-INF/views/" />
        <beans:property name="suffix" value=".jsp" />
    </beans:bean>
    
    <!-- com.example.security 하위에 있는 파일들을 다 빈으로 등록하고 찾아서 맵핑을 시킨다는 의미 -->
    <context:component-scan base-package="com.example.security" />
    
    <!-- @Secured 어노테이션 활성화, 사용 권한 제한 -->
    <security:global-method-security
        secured-annotations="enabled" />
        
</beans:beans>
cs



프로젝트의 spring폴더 하위에 security 폴더를 생성하고 폴더안에 security-context.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
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
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans 
    xmlns="http://www.springframework.org/schema/security"
    xmlns:beans="http://www.springframework.org/schema/beans" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p" 
    xmlns:util="http://www.springframework.org/schema/util"
    xsi:schemaLocation=
    "http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd">
 
 
    <!-- 정적 리소스 파일들에는 보안 설정을 하지 않음 -->
    <!-- include폴더 안에는 css같은 소스파일만 들어감 -->
    <http pattern="/include/**" security="none" />
    <http auto-config="true" use-expressions="true" 
        create-session="never">
        
        <!-- 관리자 영역 설정 , 관리자만 이 url에 접속할 수 있도록 한다.-->
        <intercept-url pattern="/admin/**" 
            access="hasRole('ROLE_ADMIN')" />
            
        <!-- 권한에 관계없이 접속 가능한 영역(guest도 접속 가능) -->
        <intercept-url pattern="/user/**" access="permitAll" />
        
        
        <!-- 로그인한 사용자 영역 -->
        <!-- 일발유저,테스터, 관리자, 손님까지 다 들어올수 있도록 한다는 의미 -->
        <intercept-url pattern="/**" access="hasAnyRole('ROLE_USER','ROLE_TEST','ROLE_ADMIN','ROLE_GUEST')" />
 
 
 
        <!-- 로그인폼 -->
        <!-- 로그인페이지, login_check는 로그인을 체크 
        userLoginSuccessHandler는 로그인을 성공했을때 처리할 코드
        userLoginFailureHandler는 로그인을 실패했을때 처리할 코드 -->
        <form-login login-page="/user/login.do" 
            login-processing-url="/user/login_check.do"
            authentication-success-handler-ref=
                "userLoginSuccessHandler"
            authentication-failure-handler-ref=
                "userLoginFailureHandler"
            username-parameter="userid" 
                password-parameter="passwd" /<!--userid는 유저아이디, passwd는 비밀번호-->
        <session-management>
        
        
        
    <!-- max-sessions="1" 동시접속 막기 (만약 2라고 설정하면 두 사람까지 접속 가능) error-if-maximum-exceeded="true" 로그인 세션 
        초과시 에러 옵션 expired-url="/user/login" 세션 만료시 이동할 주소 -->
    
        <concurrency-control max-sessions="1"
                expired-url="/user/login.do" 
                error-if-maximum-exceeded="true" />
                <!-- 만약 1명보다 더 많은 사람이 접속하려고 하면 에러메시지를 출력하게끔 설정 -->
                
        </session-management>
        
        
        
        <!-- 로그아웃 관련 처리 -->
        <logout delete-cookies=
        "JSESSIONID,SPRING_SECURITY_REMEMBER_ME_COOKIE"
            logout-success-url="/user/login.do" 
            logout-url="/user/logout.do"
            invalidate-session="true" />

        <!-- 접근권한이 없는 경우의 코드 (ex 관리자가 아니면 접속할 수 없습니다.)-->
        <access-denied-handler ref="userDeniedHandler" />

        <!-- ref는 bean의 id이다. -->
        <!-- 자동 로그인 관련 쿠키 저장, 세션이 종료된 후에도 자동 로그인할 수 있는 기능 86400 1일, 604800 7일 -->
        <remember-me key="userKey" 
        token-validity-seconds="86400" />
    </http>
    <beans:bean id="userDeniedHandler"
        class="com.example.security.service.UserDeniedHandler" />


    <beans:bean id="userLoginSuccessHandler"
        class= "com.example.security.service.UserLoginSuccessHandler" />
<!-- UserLoginSuccessHandler에는 로그인이 성공했을때 처리할 코드 작성 -->
    
<beans:bean id="userLoginFailureHandler" class= "com.example.security.service.UserLoginFailureHandler" />
<!-- UserLoginFailHandler에는 로그인이 실패 했을때 처리할 코드 작성 -->
 
    <!-- 로그인 인증을 처리하는 빈 -->
    <beans:bean id="userService" class= "com.example.security.service.UserAuthenticationService">
<!--UserAuthenticationService에는 로그인을 실제로 처리할 로직이 들어간다.  -->
 
        <beans:constructor-arg name = "sqlSession" ref = "sqlSession" />
    </beans:bean>


    <!-- 사용자가 입력한 비밀번호를 암호화된 비밀번호와 체크하는 로직이 포함됨 -->
    <authentication-manager>
        <authentication-provider user-service-ref = "userService" >
            <password-encoder ref="passwordEncoder">
                <salt-source user-property="username" />
            </password-encoder>
        </authentication-provider>
    </authentication-manager>
    
    
    <!-- 비밀번호 암호화 빈 -->
    <beans:bean id= "passwordEncoder" class= "org.springframework.security.authentication.encoding.ShaPasswordEncoder">
       <beans:constructor-arg name="strength" value="256" />
    </beans:bean>
</beans:beans>
cs



root-context.xml 작성 (트랜잭션 처리를 위해 소스탭에서 tx를 체크하기)

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
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
    
<!-- Root Context: defines shared resources visible to all other web components -->
    <!-- 오라클 연결 -->
    <bean id= "dataSource"
        class= "org.springframework.jdbc.datasource.DriverManagerDataSource">
        <!-- 드라이버 클래스 이름이 변경됨 -->
        <property name= "driverClassName" value= "net.sf.log4jdbc.sql.jdbcapi.DriverSpy"></property>
        <!--지금은 sql코드 디버깅을 위해서 driverspy를 쓰고 있음  -->
        
        
        
        <!-- 연결문자열에 log4jdbc가 추가됨 -->
        <property name="url" value=
        "jdbc:log4jdbc:oracle:thin:@localhost:1521/xe" />
        <!-- log4jdbc는 쿼리가 실행될때 로그로 전부다 출력하게 해주는 코드 -->
        <property name="username" value="spring" /<!-- 스프링 계정 아이디 -->
        <property name="password" value="1234" /<!-- 스프링 계정 비밀번호 -->
    </bean>
    
    
    <!-- SqlSessionFactory 객체 주입 -->
    <!-- mapper과 mybatis에 대한 정의 -->
    <bean id="sqlSessionFactory" class=
    "org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="configLocation" 
        value="classpath:/mybatis-config.xml"></property>
        <property name="mapperLocations" 
        value="classpath:mappers/**/*Mapper.xml"></property>
    </bean>
    
    
    <!-- SqlSession 객체 주입 -->
    <bean id="sqlSession" class"org.mybatis.spring.SqlSessionTemplate" destroy-method="clearCache">
        <constructor-arg name="sqlSessionFactory" ref="sqlSessionFactory">
        
        </constructor-arg>
    </bean>
    
    <!-- 트랜잭션 처리를 할때 transactionManager라는 태그를 만들 예정-->
    <!-- 트랜잭션 어노테이션을 처리해주는 코드 -->
    <tx:annotation-driven transaction-manager="transactionManager" />
    
    
    <!-- transactionManager는 DataSourceTransactionManager는 클래스를 지정-->
    <bean id"transactionManager"
        class"org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
</beans>
cs





log4j.xml 은 프로젝트 생성당시 만들어진것을 그대로 사용.



mybatis-config.xml 은 xml파일을 새로 생성해서 사용. (생성만하고 그대로 놔둠)



log4jdbc.log4j2.properties 파일을 추가

1
log4jdbc.spylogdelegator.name=net.sf.log4jdbc.log.slf4j.Slf4jSpyLogDelegator //sql 명령어를 로깅 처리할 수 있는 코드
cs



logback.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
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <!-- log4jdbc-log4j2 -->
    <logger name="jdbc.sqlonly"        level="DEBUG"/>
    <logger name="jdbc.sqltiming"      level="INFO"/>
    <logger name="jdbc.audit"          level="WARN"/>
    <logger name="jdbc.resultset"      level="ERROR"/>
    <logger name="jdbc.resultsettable" level="ERROR"/>
    <logger name="jdbc.connection"     level="INFO"/>
    
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <layout class="ch.qos.logback.classic.PatternLayout">
            <pattern>%d{HH:mm:ss.SSS} [%thread] %-4level [%logger.%method:%line]-
                %msg%n</pattern>
        </layout>
    </appender>
 
    <appender name="LOGFILE"
        class="ch.qos.logback.core.rolling.RollingFileAppender">
        <file>/WEB-INF/logback.log</file>
        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
            <fileNamePattern>logback.%d{yyyy-MM-dd}.log</fileNamePattern>
            <!-- 30일 지난 파일은 삭제한다. -->
            <maxHistory>30</maxHistory>
        </rollingPolicy>
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} %-4level [%logger.%method:%line]
                - %msg %n</pattern>
        </encoder>
    </appender>
 
    <!-- 로그의 레벨( 지정된 로그 레벨 이상만 수집 ) : DEBUG < INFO < WARN < ERROR < FATAL -->
    <logger name="myweb" additivity="false">
        <level value="INFO" />
        <appender-ref ref="LOGFILE" />
        <appender-ref ref="CONSOLE" />
    </logger>
 
    <root>
        <level value="INFO" />
        <appender-ref ref="CONSOLE" />
    </root>
 
</configuration>
 
cs




회원가입, 로그인, 로그아웃만 작성할 예정


UserDTO.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.security.model.dto;
 
import java.util.Collection;
 
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;
 
public class UserDTO extends User {
    
    private String userid;
    
    public UserDTO(String username, String password, 
            boolean enabled, boolean accountNonExpired,
            boolean credentialsNonExpired, 
            boolean accountNonLocked, 
            Collection<extends GrantedAuthority> authorities,
            String userid) {
        
    
        super(username, password, enabled, accountNonExpired
                , credentialsNonExpired, accountNonLocked, authorities);
        //super()안에 들어가있는 필드들은 user클래스에 보내는 코드
        this.userid = userid;
    }
 
    
    public String getUserid() {
        return userid;
    }
 
    public void setUserid(String userid) {
        this.userid = userid;
    }
 
    @Override
    public String toString() {
        return "UserDTO [userid=" + userid + "]";
    }
}
cs



DAO를 생성


UserDAO.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package com.example.security.model.dao;
 
import java.util.Map;
 
public interface UserDAO {
    
    //회원가입 처리
    public int insertUser(Map<String,String> map);
    
    //로그인 처리
    public Map<String,Object> selectUser(String userid);
    
}
 
cs



UserDAOImpl.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
package com.example.security.model.dao;
 
import java.util.Map;
 
import javax.inject.Inject;
 
import org.apache.ibatis.session.SqlSession;
import org.springframework.stereotype.Repository;
 
@Repository //dao 빈으로 등록
public class UserDAOImpl implements UserDAO {
    
    @Inject     //mapper을 사용하기 위해 의존성을 주입
    SqlSession sqlSession;
    
    @Override
    public int insertUser(Map<StringString> map) {
        return sqlSession.insert("user.insertUser", map);
        //users테이블에 map에 담아놓은 레코드를 추가하는 메소드
    }
 
    @Override
    public Map<String, Object> selectUser(String userid) {
        return sqlSession.selectOne("user.selectUser", userid);
        //로그인을 확인하는 메소드
    }
 
}
 
cs



src/main/resources 폴더 하위에 mappers 폴더를 생성하고, 샘플 프로젝트에서 샘플 mapper을 복사하고 이름을 userMapper.xml로 바꾼다.



userMapper.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
<?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="user">
 
    <insert id="insertUser">
        insert into users
        values (#{userid}, #{passwd}, #{name}, 1, #{authority})
        <!-- 회원가입 쿼리, id, 비밀번호, 이름 , 신규가입이므로 1이 들어감,  그리고 관리자계정인지 일반계정인지 확인후 들어감-->
    </insert>
    
    <select id="selectUser" resultType="java.util.Map">
    
        select 
        userid as username, <!-- 스프링에서 체크하는 필드명과 맞춘 것 -->
        passwd as password, <!-- 스프링에서 체크하는 필드명과 맞춘 것 -->
            name, 
            enabled, 
            authority
        from users <!-- users테이블로부터 검색 -->
        where userid=#{userid} <!-- userid가 내가 입력한 userid와 같은 경우 -->
        <!-- 여기서 검색한 쿼리는 hashmap로 저장이 되어서 dao로 보낸다.-->
    </select>
</mapper>
cs




UserAuthentivationService.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
package com.example.security.service;
 
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
 
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
 
import com.example.security.model.dto.UserDTO;
 
//로그인 처리 클래스
public class UserAuthenticationService implements UserDetailsService {
//UserDetailsService는 스프링 프레임 워크에 내장되어있는 클래스
    
    private SqlSessionTemplate sqlSession;
    public UserAuthenticationService() {     }
    public UserAuthenticationService(
        SqlSessionTemplate sqlSession) {
        this.sqlSession=sqlSession;
    }
    
    
    //로그인 인증을 처리하는 코드
    //파라미터로 입력된 아이디값에 해당하는 테이블의 레코드를 읽어옴
    //정보가 없으면 예외를 발생시킴
    //정보가 있으면 해당 정보가 map(dto)로 리턴된다.
    
        @Override
        public UserDetails loadUserByUsername(String userid) 
            throws UsernameNotFoundException {
        
        //사용자 아이디 확인 (mapper에서 map에 담아 전달된 사용자의 아이디)
        Map<String,Object> user=sqlSession.selectOne("user.selectUser", userid);
        
        //아이디가 없으면 예외 발생
        if(user==nullthrow new UsernameNotFoundException(userid);
        
        //사용권한 목록
        List<GrantedAuthority> authority=new ArrayList<>();
        // 오라클에서는 필드명을 대문자로 적어야 함
        // 오라클에서는 BigInteger 관련 오류가 발생할 수 있으므로 아래와 같이 처리 
        // 속성이름을 대문자로 작성해야 에러가 발생하지 않는다.
        //(Integer)Integer.valueOf(user.get("ENABLED").toString()) == 1
        
    authority.add(
new SimpleGrantedAuthority(user.get("AUTHORITY").toString())); 
 
        //필드명은 대문자로
        return new UserDTO(user.get("USERNAME").toString(),
                user.get("PASSWORD").toString(),
                
                //1과 같으면 사용가능한 계정이고, 0이면 사용불가능한 계정이다.
                
                //ENABLED는 1이라는 의미
                (Integer)Integer.valueOf(user.get("ENABLED").toString())==1,
                true,true,true,authority,
                user.get("USERNAME").toString());
    }
 
}
cs




UserDeniedHandler.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
package com.example.security.service;
 
import java.io.IOException;
 
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;
 
public class UserDeniedHandler 
    implements AccessDeniedHandler {
 
    //사용권한이 없을 때 지정한 페이지로 이동
    //관리자기능의 일반 사용자가 접근할때 에러를 출력하는 코드
    //security-context에 access-denied-handler로 설정되어있기 때문에 자동적으로 호출이 된다.
    @Override
    public void handle(HttpServletRequest req
            , HttpServletResponse res, AccessDeniedException ade)
            throws IOException, ServletException { 
        req.setAttribute("errMsg"
                "관리자만 사용할 수 있는 기능입니다.");
        
        //위의 경고메시지를 출력하고 denied.jsp로 강제로 이동하게 한다.
        String url="/WEB-INF/views/user/denied.jsp";
        RequestDispatcher rd=req.getRequestDispatcher(url);
        rd.forward(req, res);
//        req.getRequestDispatcher(
//                "/WEB-INF/views/user/denied.jsp").forward(req, res);
    }
 
}
cs



UserLoginFailureHandler.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
package com.example.security.service;
 
import java.io.IOException;
 
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
 
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
 
public class UserLoginFailureHandler 
    implements AuthenticationFailureHandler {
 
        //로그인이 실패했을 때의 처리
        @Override
        public void onAuthenticationFailure(
                HttpServletRequest request, 
                HttpServletResponse response,
                AuthenticationException exception) 
                throws IOException, ServletException {
        
        //request 영역에 변수 저장
        request.setAttribute("errMsg",
                "아이디 또는 비밀번호가 일치하지 않습니다.");
        
        //forward
        request.getRequestDispatcher(
                "/WEB-INF/views/user/login.jsp")
                    .forward(request, response);
        
    }
    
}
cs



HomeController.java 에 있는 home 메소드에 RequestMapping "/" 가 UseController.java의 맵핑 url과 동일하기


때문에 home 메소드를 주석처리 한다.



UserController.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
package com.example.security.controller;
 
import java.util.HashMap;
import java.util.Map;
 
import javax.inject.Inject;
 
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
 
import com.example.security.model.dao.UserDAO;
import com.example.security.service.ShaEncoder;
 
@Controller //컨트롤러 빈
public class UserController {
 
    @Inject
    ShaEncoder shaEncoder; //암호화 빈 
    
    @Inject
    UserDAO userDao; 
    
    @RequestMapping("/"//시작 페이지
    public String home(Model model) {
        return "home"//home.jsp로 이동
    }
    
    //로그인 페이지로 이동
    @RequestMapping("/user/login.do")
    public String login() {
        return "user/login";
    }

    //회원가입 페이지로 이동
    @RequestMapping("/user/join.do")
    public String join() {
        return "user/join";
    }
    
    //회원가입 처리     
    @RequestMapping("/user/insertUser.do")
    public String insertUser(@RequestParam String userid, 
            @RequestParam String passwd,
            @RequestParam String name, 
            @RequestParam String authority) {
        
        //비밀번호 암호화
        String dbpw=shaEncoder.saltEncoding(passwd, userid);
        
        Map<String,String> map=new HashMap<>();
        map.put("userid", userid);
        map.put("passwd", dbpw);
        map.put("name", name);
        map.put("authority", authority);
        // affected rows, 영향을 받은 행의 수가 리턴됨
        int result=userDao.insertUser(map);
        return "user/login"// login.jsp로 이동
    }
    
    //관리자 영역 페이지    
    @RequestMapping("/admin/")
    public String admin() {
        return "admin/main";
    }
}
cs



views 폴더 하위에 include 폴더를 만들고 css폴더 하위에 main.css 추가


include 폴더 하위에 header.jsp 추가



main.css

1
2
3
4
5
.@charset "UTF-8";
a:link {text-decoration: none; color:blue; }
a:hover {text-decoration: underline; color: red;}
a:visited {text-decoration: none; }
a:active {text-decoration: none; color:yellow; }
cs



header.jsp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
.<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
 
 
<!-- 태그 라이브러리 선언 -->
<%@ taglib prefix="c"
uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fmt"
uri="http://java.sun.com/jsp/jstl/fmt" %>
<%@ taglib prefix="fn" 
uri="http://java.sun.com/jsp/jstl/functions" %>
 
 
<!-- 컨텍스트 패스 설정 -->
<c:set var="path" value="${pageContext.request.contextPath}"/>
 
 
<!-- js, css 연결 -->
<script src="http://code.jquery.com/jquery-3.2.1.min.js">
</script>
<link rel="stylesheet" href="${path}/include/css/main.css">
cs



view 폴더하위에 user폴더 하위에 login.jsp 파일 생성


로그인 화면을 출력할 (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
.<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!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" %>
 
<script type="text/javascript">
function join(){
    location.href="${path}/user/join.do";
}
</script>
 
</head>
<body>
<h2>로그인 페이지</h2>
<span style="color:red;">${errMsg}</span>
<!-- 컨트롤러에 보면 login_check.do가 없지만 security-context파일에 가서 확인해보면
check.do가 있는것을 확인할 수 있다. (login-processing-url에 지정을 해놓았다.)-->
<form action="${path}/user/login_check.do" method="post">
<table>
    <tr>
        <td>아이디</td>
        <td><input name="userid"></td>
    </tr>
    <tr>
        <td>비밀번호</td>
        <td><input type="password" name="passwd">
            <input name="_spring_security_remember_me"
                type="checkbox">자동 로그인</td>
    </tr>
    <tr>
        <td colspan="2" align="center">
            <input type="submit" value="로그인">
            <input type="button" value="회원가입" onclick="join()">
        </td>
    </tr>
</table>
</form>
</body>
</html>
cs



회원가입 페이지 (join.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
.<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!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" %>
</head>
<body>
<h2>회원가입</h2>
<form action="${path}/user/insertUser.do" method="post">
<table>
    <tr>
        <td>아이디</td>
        <td><input name="userid"></td>
    </tr>
    <tr>
        <td>비밀번호</td>
        <td><input type="password" name="passwd"></td>
    </tr>
    <tr>
        <td>이름</td>
        <td><input name="name"></td>
    </tr>
    <tr>
        <td>사용권한</td>
        <td>
            <select name="authority">
            <!-- 사용권한은 일반사용자와 관리자 2가지로 나눈다. -->
                <option value="ROLE_USER">일반사용자</option>
                <option value="ROLE_ADMIN">관리자</option>
            </select>
        </td>
    </tr>
    <tr>
        <td colspan="2" align="center">    
            <input type="submit" value="회원가입">
            <!-- 회원가입 버튼을 누르면 컨트롤러에 insertUser.do로 넘어간다.-->
        </td>
    </tr>
</table>
</form>
</body>
</html>
cs



데이터베이스에서 users 테이블의 내용을 검색해보면 패스워드가 암호화되어서 들어가있는 것을 확인할 수 있다.


web.xml을 보면 한글처리를 하는 코드 밑에 스프링 시큐리티에서 처리하도록 하는 필터가 있는데, 


이렇게 하게되면 한글처리가 잘 되기때문에 한글이 깨진다면 이렇게 하면 된다.



  비밀번호 암호화


  join.jsp에서 입력된 비밀번호 값이 컨트롤러에 맵핑되서 암호화가 된 후에 테이블에 저장.




home.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 http-equiv="Content-Type" content="text/html; charset=UTF-8">
<%@ include file="include/header.jsp" %>
<title>Home</title>
</head>
<body>
    <h2>Welcome!</h2>
    <h2>${msg}</h2>
    <a href="${path}/admin/">관리자 페이지</a><br>
    <a href="${path}/user/logout.do">로그아웃</a>
</body>
</html>
cs



view폴더 하위에 admin디렉토리를 만들고 main.jsp 파일 생성

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<%@ include file="../include/header.jsp" %>
 
<!-- 권한이 없는 사용자가 권한이 필요한 페이지에 들어갔을때 출력되는 페이지 -->
<!-- 에러메시지가 출력되고 3초후에 메인페이지로 이동하게 된다. -->
 
<!-- 3초후 메인페이지로 이동 -->
<meta http-equiv="refresh" content="3,${path}">
<title>Insert title here</title>
 
</head>
<body>
<p>${errMsg}</p>
</body>
</html>
cs


user폴더 하위에 denied.jsp 파일 생성


(권한이 없는 사용자가 권한이 필요한 페이지에 들어갔을때 출력되는 페이지)

(에러메시지가 출력되고 3초후에 메인페이지로 이동하게 된다.)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<%@ include file="../include/header.jsp" %>
 
<!-- 권한이 없는 사용자가 권한이 필요한 페이지에 들어갔을때 출력되는 페이지 -->
<!-- 에러메시지가 출력되고 3초후에 메인페이지로 이동하게 된다. -->
 
<!-- 3초후 메인페이지로 이동 -->
<!--refresh쓰고, content="숫자 , ${path}"를 쓰면 "숫자"초 후에 path경로로 이동된다는 의미-->
<meta http-equiv="refresh" content="3,${path}">
<title>Insert title here</title>
 
</head>
<body>
<p>${errMsg}</p>
</body>
</html>
cs



시큐리티를 사용하면 url로 직접 쳐서 관리자페이지로 들어가는 것을 막을 수 있고 (보안때문에)


그리고, 뒤로가기를 눌렀을때 사용자 정보가 보여지는 것을 막을 수 있다.




  -로그인 처리 순서-


  login.jsp 페이지에서 로그인을 하려고 하면 login_check.do로 이동해야하는데 컨트롤러에는 이 url이 없다.


  이 url은 security-context.xml에 태그에 담겨져 있기 때문에 이 태그를 거쳐서 UserAuthenticationService.java로 오게된다.


  이 페이지에서 loadUserByUsername() 메소드를 호출해서 기존 테이블에 저장된 값하고, 사용자가 입력한 값을 비교해서


  틀리면 에러를 내고, 맞았으면 success를 낸다.



:

Spring SQL Server 연동 (실습)

Back-End/Spring 2019. 7. 12. 11:55

SQL Server 연동 실습 예제


1. SQL Server에 데이터베이스 및 테이블 생성


   Microsoft SQL Server Management Studio 실행


   인증 : SQL Server 인증


   로그인 : sa


   암호 : 1234



  

  데이터베이스 만드는 방법


  데이터베이스 우클릭 => 새 데이터 베이스 => web라는 이름의 데이터베이스 생성




  

  참고 -


  기존의 데이터베이스만 지우고, 같은 이름의 데이터베이스를 만들때 속성 이름이 같으면 에러가 발생할 수 있으니


  속성 이름을 다르게 하고 만들면 에러가 발생하지 않는다.




아래 그림처럼 데이터베이스를 만들고 "새 쿼리" 버튼을 눌러 쿼리를 입력한다.





-데이터베이스 쿼리 작성-


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
--web데이터베이스를 사용하겠다는 쿼리
--마우스로 드래그 하고 f5를 누르면 쿼리가 실행된다.
use web;
 
 
--설문문항 테이블
create table survey(
--identity는 sql server에서 일련번호를 매길때 사용하는 옵션
--(1,1)은 1부터 시작해서 1씩 증가한다는 의미이다.
--일련번호를 기본키로 지정함
survey_idx int identity(1,1primary key,
--sql server에서는 varchar2는 없고 varchar만 있다. varchar2는 오라클에만 있다.
question varchar(500),
ans1 varchar(100),
ans2 varchar(100),
ans3 varchar(100),
ans4 varchar(100),
--status는 기본값이 Y라는 뜻이다.
status char(1default 'Y'
);
 
 
--문제번호는 자동증가가되므로 넣지 않았다.
insert into survey (question, ans1, ans2, ans3, ans4) values
('좋아하는 과일은 무엇입니까?','사과','배','수박','참외');
 
 
select * from survey;
 
 
--응답 테이블 생성
create table answer(
answer_idx int identity(1,1primary key--응답 일련번호 1부터 시작해 1씩 증가함, 기본키로 설정함
survey_idx int
num int
-- 문제번호에 대해 응답한 번호
);
 
 
--테이블이 잘 만들어졌는지 확인하기 위해 값들을 하나씩 넣어본다.
--응답 번호를 하나씩 넣어본다.
insert into answer (survey_idx, num) values (1,1);
insert into answer (survey_idx, num) values (1,2);
insert into answer (survey_idx, num) values (1,2);
insert into answer (survey_idx, num) values (1,2);
insert into answer (survey_idx, num) values (1,3);
insert into answer (survey_idx, num) values (1,4);
insert into answer (survey_idx, num) values (1,4);
 
 
--테이블 목록을 확인할때는 infomation_schema가 있는데 거기서 
--테이블 목록을 확인한다는 쿼리이다.
select distinct table_name from information_schema.tables;
 
 
 
--설문조사의 결과를 확인하는 쿼리--

select survey_idx,num,count(num) sum_num, 
--ex) 1번 문제 (survey_idx)에 대해 1번(num)으로 응답한 사람이 1명(sum_num)
--    이므로 정답률(rate)는 14.3%라는 뜻.  
 
 
round(--round는 반올림 하라는뜻, 정답률은 소수점이므로 반올림을 해야한다.
        --맨뒤에 있는 ,1은 소수 둘째자리에서 반올림을 해서 소수 첫째자리까지만
        --출력하게 하라는 뜻.
 
    (select count(*from answer 
    where survey_idx=a.survey_idx and num=a.num) *100.0 --분자
    --응답 테이블로부터 응답테이블의 설문번호와 설문테이블의 설문번호가 일치함과 동시에
    --선택한 답의 번호가 응답 테이블의 선택한 답의 번호와 일치하는 것에 count(개수)를 파악하고 백분율
    --이기 때문에 100을 곱한다.
 
 
    / (select count(*from answer                    --분모
        where survey_idx=a.survey_idx),1) rate
        --응답 테이블로부터 설문테이블의 문항 번호와 응답테이블의 문항번호가 같은것에 개수를 검색한다.
        --그리고 분모와 분자 그리고 100을 곱해서 나온 백분율 (소수점값) 값뒤에 ,1이 써있으므로,
        --소수 둘째자리에서 반올림해서 소수 첫째자리까지만 나오게해서 rate에 넣는다.
 
 
from answer a --answer테이블 (약자로 a라고 표현) 로부터 검색 
where survey_idx=1 --조건 : 문항 번호가 1인것.
group by survey_idx, num --  --번호별로 하기 위해서 group by를 사용
order by num; --num의 내림차순으로 정렬시킨다.

cs



-Spring Project 생성-


  Spring Legacy Project 생성


  프로젝트 이름 : spring05_mssql


  패키지 이름 : com.example.spring05 로 한다.




  - 기본 구조 -



    프로젝트를 실행하면 컨트롤러에 있는 "/"로 맵핑이 되서 show_survey() 메소드가 실행되어서 survey테이블에 


    저장되어 있는 문제를 Dao와 mapper을 거쳐서survey DTO 타입으로 dto 변수에 저장되고, 


    main페이지로 dto값을 같이 보낸다.main.jsp 페이지가 실행되고, 아까 보낸 dto값을 출력해서 문제와 보기들을 출력한다.


    보기를 선택하고 "투표" 버튼을 누르면 hidden 타입으로 내가 투표한 보기의 번호 (survey_idx) 가 컨트롤러의 save_survey.do로 맵핑된다.


    컨트롤러에 save_survey.do로 맵핑된 메소드에서는 dto에 저장된 (폼에서 입력받은 자료) 자료를 Dao와 mapper을 거쳐서


    answer테이블에 저장하고, success jsp 페이지로 리턴한다.


    success jsp페이지에서는 (Home) 시작페이지로 이동시키는 링크를 걸고, 링크를 클릭하면 시작페이지인 main.jsp 페이지로 이동


    main.jsp 페이지에서 "결과 확인" 버튼을 누르면 자바스크립트 함수인 show_result()가 실행되서

  

    컨트롤러에 show_result.do로 맵핑되고, survey_idx값 (문항번호)를 같이 넘긴다.


    show_result.do로 맵핑된 메소드에선 hashmap에 설문문항 내용과, 설문응답 리스트를 저장하고, result.jsp 페이지로 이동시키고, map를 넘긴다.


    result.jsp 페이지에선 map의 dto에 담긴 문제 및 list에 담긴 문항, 응답수, 응답비율을 차례로 출력시키고, home로 가는 링크를 추가시킨다.


 




프로젝트를 만들고 pom.xml을 열고, 라이브러리에 버전을 수정하고 아까 sql server에 jar파일을 로컬저장소에 추가했기 때문에


불러와야한다.


pom.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

<properties>
        <java-version>1.8</java-version>
        <org.springframework-version>5.1.4.RELEASE</org.springframework-version>
        <org.aspectj-version>1.9.2</org.aspectj-version>
        <org.slf4j-version>1.7.25</org.slf4j-version>
    </properties>
    
    <!-- 로컬 저장소 추가 -->
    <!-- 아까 sql server jar파일이 메이븐 저장소에 없어서 로컬저장소에 추가했기 때문에 그걸 알려줘야 한다. -->
    <repositories>
        <repository>
            <id>local</id>
            <name>local</name><!-- user은 사용자 계정이고 한글로 쓰면 안된다. -->
            <url>file://C:/Users/user/.m2/repository</url>
        </repository>
    </repositories>

    <dependencies>
    <!-- SQL Server 라이브러리 선언 -->
        <dependency>
            <groupId>com.microsoft.sqlserver</groupId>
            <artifactId>sqljdbc4</artifactId>
            <version>4.0</version>
        </dependency>

cs



프로젝트 우클릭 => Java Build Path와 Java Compiler, Project Facets를 확인해서 Java 버전을 다 1.8버전으로 맞춰준다.


맞춰주고 난 후에 에러가 나면 Project update를 한다.




테스트용 페이지 생성


home.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" %>
    <!-- 한글깨짐 방지를 위해  문자셋설정 코드를 추가함 -->
    
    
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ page session="false" %>
<html>
<head>
 
<meta http-equiv = "Content-Type" content = "text/html; charset=UTF-8">
 
<title>Home</title>
</head>
<body>
<h1>
    Hello world!  
</h1>
 
<P>  The time on the server is ${serverTime}. </P>
</body>
</html>
 
cs



web.xml (한글처리를 위한 인코딩 필터 추가)

1
2
3
4
5
6
7
8
9
10
11
12
13

<!-- 한글 인코딩을 위한 필터 선언 -->
    <filter>
        <filter-name>encoding</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
    </filter>

    <filter-mapping>
        <filter-name>encoding</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

cs



servlet-context는 서블릿에 관련된 설정을 모아놓은 xml이고,


root-context는 서블릿을 제외한 나머지 설정들을 모아놓은 xml이다.


servlet-context는 따로 바꿀필요가 없고, root-context를 보면 데이터베이스 연동 설정을 해주어야 한다.



root-context.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
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
    xmlns:mybatis-spring="http://mybatis.org/schema/mybatis-spring"
    xmlns:mongo="http://www.springframework.org/schema/data/mongo"
    xsi:schemaLocation="http://mybatis.org/schema/mybatis-spring
http://mybatis.org/schema/mybatis-spring-1.2.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.1.xsd">
 
    <!-- Root Context: defines shared resources visible to all other web components -->
    <bean id="dataSource"class="org.springframework.jdbc.datasource.DriverManagerDataSource">
 
        <!-- 드라이버 클래스 이름이 변경됨 -->
        <property name="driverClassName"  <!-- 드라이버 클래스 이름 -->
        value="net.sf.log4jdbc.sql.jdbcapi.DriverSpy"> <!--드라이버 클래스 이름이 변경되는것이 로그에 찍힌다는 의미 -->
</property>
 
        <!-- 연결문자열에 log4jdbc가 추가됨 --> 중요!!
        <!--SQL Server에 접속하는 코드, 아이디와 비밀번호, 데이터베이스 이름-->
<!-- value에 log4jdbc가 들어있기 때문에, 로그가 찍혀 과정이 출력되게 된다. -->
<property name="url"
            value=
"jdbc:log4jdbc:sqlserver://localhost:1433;DatabaseName=web" /> <!--로컬호스트 기본 포트번호인 1433으로 web 데이터베이스를 연결 -->
        <property name="username" value="sa" /> <!-- id는 sa 라고 한다 -->
        <property name="password" value="1234" /> <!-- 비밀번호는 1234 라고 한다 -->
    </bean>
 

  <!-- SqlSessionFactory 객체 주입 -->
<!-- mybatis를 이용해서 SQL Server와 연동을 할 예정 -->
    <bean id="sqlSessionFactory" 
    class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource" />
        <property name="configLocation" 
        value="classpath:/mybatis-config.xml"></property>
        <property name="mapperLocations" 
        value="classpath:mappers/**/*Mapper.xml"></property>
    </bean>
 

  <!-- SqlSession 객체 주입 -->
    <bean id="sqlSession" 
    class="org.mybatis.spring.SqlSessionTemplate"
        destroy-method="clearCache">
        <constructor-arg name="sqlSessionFactory" 
        ref="sqlSessionFactory"></constructor-arg>
    </bean>
</beans>


cs



SurveyDTO.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
package com.example.spring05.model.dto;
 
public class SurveyDTO {
    
    //설문조사 문항을 저장할 필드들
    private int survey_idx;
    private String question;
    private String ans1;
    private String ans2;
    private String ans3;
    private String ans4;
    private String status;
    //getter,setter,toString()
    
    public int getSurvey_idx() {
        return survey_idx;
    }
    public void setSurvey_idx(int survey_idx) {
        this.survey_idx = survey_idx;
    }
    public String getQuestion() {
        return question;
    }
    public void setQuestion(String question) {
        this.question = question;
    }
    public String getAns1() {
        return ans1;
    }
    public void setAns1(String ans1) {
        this.ans1 = ans1;
    }
    public String getAns2() {
        return ans2;
    }
    public void setAns2(String ans2) {
        this.ans2 = ans2;
    }
    public String getAns3() {
        return ans3;
    }
    public void setAns3(String ans3) {
        this.ans3 = ans3;
    }
    public String getAns4() {
        return ans4;
    }
    public void setAns4(String ans4) {
        this.ans4 = ans4;
    }
    public String getStatus() {
        return status;
    }
    public void setStatus(String status) {
        this.status = status;
    }
    @Override
    public String toString() {
        return "SurveyDTO [survey_idx=" + survey_idx + ", question=" + question + ", ans1=" + ans1 + ", ans2=" + ans2
                + ", ans3=" + ans3 + ", ans4=" + ans4 + ", status=" + status + "]";
    }
    
}
 
cs



AnswerDTO.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
package com.example.spring05.model.dto;
 
//사용자 응답 저장 클래스
 
public class AnswerDTO {
    
    private int answer_idx; //응답 일련번호
    private int survey_idx;    //문제 번호
    private int num;        //선택한 번호
    private int sum_num;    //카운트 (그 답을 선택한 사람의 숫자)
    private double rate;    //카운트에 대한 백분율 비율
    //getter,setter,toString()
    
    public int getAnswer_idx() {
        return answer_idx;
    }
    public void setAnswer_idx(int answer_idx) {
        this.answer_idx = answer_idx;
    }
    public int getSurvey_idx() {
        return survey_idx;
    }
    public void setSurvey_idx(int survey_idx) {
        this.survey_idx = survey_idx;
    }
    public int getNum() {
        return num;
    }
    public void setNum(int num) {
        this.num = num;
    }
    public int getSum_num() {
        return sum_num;
    }
    public void setSum_num(int sum_num) {
        this.sum_num = sum_num;
    }
    public double getRate() {
        return rate;
    }
    public void setRate(double rate) {
        this.rate = rate;
    }
    @Override
    public String toString() {
        return "AnswerDTO [answer_idx=" + answer_idx + ", survey_idx=" + survey_idx + ", num=" + num + ", sum_num="
                + sum_num + ", rate=" + rate + "]";
    }
    
}
 
cs



SurveyDAO.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.spring05.model.dao;
 
import java.util.List;
 
import com.example.spring05.model.dto.AnswerDTO;
import com.example.spring05.model.dto.SurveyDTO;
 
public interface SurveyDAO {
    
    
    //설문문항 보기, 문제보기
    public SurveyDTO showSurvey(int survey_idx);
    
    
    //설문응답 처리, 응답 내용 저장
    public void save(AnswerDTO dto);
    
    
    //설문결과 목록 보기
    public List<AnswerDTO> showResult(int survey_idx);
    
}
 
cs



SurveyDAOImpl.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
package com.example.spring05.model.dao;
 
import java.util.List;
 
import javax.inject.Inject;
 
import org.apache.ibatis.session.SqlSession;
import org.springframework.stereotype.Repository;
 
import com.example.spring05.model.dto.AnswerDTO;
import com.example.spring05.model.dto.SurveyDTO;
 
@Repository //dao bean
public class SurveyDAOImpl implements SurveyDAO {
 
    
    @Inject //mybatis 실행을 위한 객체를 주입, 의존관계를 주입 (DI)
    SqlSession sqlSession;
    
    
    @Override
    public SurveyDTO showSurvey(int survey_idx) {//문제 보기
        //selectOne 레코드 1개, selectList 레코드 리스트
        //문제번호를 보내서 select쿼리를 보내서 문제를 받아옴
        return sqlSession.selectOne("show_survey", survey_idx); 
    }
 
    
    @Override
    public void save(AnswerDTO dto) { //응답을 저장
        sqlSession.insert("save_answer", dto);
    }
 
    
    @Override
    public List<AnswerDTO> showResult(int survey_idx) {    //설문 결과
        //리스트를 받아와야 하기때문에 selectList()를 사용한다.
        return sqlSession.selectList("show_result", survey_idx);
    }
 
}
cs



root-context파일에 가보면 mapper의 경로가 나와있는데, 이 경로대로 mapper을 만들어주어야 mapper이 실행이 된다.


root-context중 일부

1
2
<property name="mapperLocations" 
        value="classpath:mappers/**/*Mapper.xml"></property>
cs



경로에 맞춰서 Mapper 파일 생성


surveyMapper.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
<?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="survey">
    
    <!-- 문제를 가져오는 sql 쿼리 -->
    <select id="show_survey" resultType="com.example.spring05.model.dto.SurveyDTO">
    
    <!--문항테이블로부터 전체항목을 검색 (내가 선택한 문제번호와 저장된 문제 번호가 같은경우)-->
    <!-- 여기서 검색된 항목은 dto타입으로 변환되서 넘겨준다. -->
        select * from survey
        where    survey_idx=#{survey_idx}
    </select>
    
    <insert id="save_answer">
    <!-- answer테이블에 문제번호와 응답한 번호를 저장한다. -->
        insert into answer (survey_idx, num) values 
            (#{survey_idx},#{num})
    </insert>
    
    <select id="show_result"
        resultType="com.example.spring05.model.dto.AnswerDTO">
        <!-- 아래의 쿼리를 실행해서 결과값을 AnswerDTO 타입으로 리턴함 -->
        
            <!--  ex) 1번 문제 (survey_idx)에 대해 1번(num)으로 응답한 사람이 1명(sum_num) 이므로 
정답률(rate)는 14.3%라는 뜻.-->        
        select
            survey_idx, num, count(num) sum_num,
            
                
            round(
            <!--  round는 반올림 하라는뜻, 정답률은 소수점이므로 반올림을 해야한다.
            맨뒤에 있는 ,1은 소수 둘째자리에서 반올림을 해서 소수 첫째자리까지만
            출력하게 하라는 뜻.-->
            
            
        <!-- 응답 테이블로부터 응답테이블의 설문번호와 설문테이블의 설문번호가 일치함과 동시에
        선택한 답의 번호가 응답 테이블의 선택한 답의 번호와 일치하는 것에 count(개수)를 파악하고 백분율
        이기 때문에 100을 곱한다. -->    
             (select count(*) from answer
                    where survey_idx=a.survey_idx
                        and num=a.num)*100.0 <!--분자-->
                        
                            
            <!--응답 테이블로부터 설문테이블의 문항 번호와 응답테이블의 문항번호가 같은것에 개수를 검색한다.
            그리고 분모와 분자 그리고 100을 곱해서 나온 백분율 (소수점값) 값뒤에 ,1이 써있으므로,
            소수 둘째자리에서 반올림해서 소수 첫째자리까지만 나오게해서 rate에 넣는다. -->                    
                    / (select count(*) from answer
                    where survey_idx=a.survey_idx),1) rate <!-- 분모 -->
                    
                                    
        from answer a                      <!-- answer테이블 (약자로 a라고 표현) 로부터 검색 -->
        where survey_idx=#{survey_idx}     <!-- 조건 : 문항 번호가 1인것. -->
        group by survey_idx, num          <!-- 번호별로 하기 위해서 group by를 사용 -->
        order by num                     <!-- num의 내림차순으로 정렬시킨다. -->
    
</select>
</mapper>
cs



mybatis관련 파일들을 복사 ( log4j.xml , log4jdbc.log4j2.properties , logback.xml , mybatis-config.xml )


이번에는 서비스 계층을 만들지 않고, 컨트롤러에서 곧바로 DAO를 호출해서 사용할 예정


컨트롤러를 생성



SurveyController.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
package com.example.spring05.controller;
 
import java.util.HashMap;
import java.util.List;
import java.util.Map;
 
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
 
import com.example.spring05.model.dao.SurveyDAO;
import com.example.spring05.model.dto.AnswerDTO;
import com.example.spring05.model.dto.SurveyDTO;
 
@Controller //controller bean
public class SurveyController {
 
    
    //@Inject //의존관계 주입
    @Autowired //스프링 프레임워크 의존관계 주입 어노테이션
    SurveyDAO surveyDao;
        
    
    //시작페이지는 main.jsp로 가서 문제화면을 출력하는 메소드
    @RequestMapping("/"// http://localhost/spring05
    public ModelAndView show_survey() {  //문제를 보여주는 메소드
        SurveyDTO dto=surveyDao.showSurvey(1); //1번 설문을 dto로 저장해서 보낸다.
        // main.jsp로 포워딩, 전달할 변수명 dto
        return new ModelAndView("main","dto",dto);
    }
    
    
    @RequestMapping("/save_survey.do"//응답 내용을 저장하는 메소드
    public String save_survey( @ModelAttribute AnswerDTO dto ) {
        surveyDao.save(dto); //테이블에 저장 (form에서 입력받은걸 받아서)
        return "success"//success.jsp로 포워딩
    }
    
    
    @RequestMapping("/show_result.do"

//설문 결과
    public ModelAndView show_result() {
        
        
        Map<String,Object> map=new HashMap<>();
        
        //설문문항 내용 (1번 설문문항의 내용을 dto에 저장)
        SurveyDTO dto=surveyDao.showSurvey(1);
        
        //설문응답 리스트
        
        List<AnswerDTO> items=surveyDao.showResult(1);
        
        //map에 자료 저장
        map.put("dto", dto);
        map.put("list", items);
        
        //result.jsp로 포워딩, 변수명 : map
        return new ModelAndView("result""map", map);    
    }    
}
cs



컨트롤러에서 리턴할 View ( main,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
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
 
<script>
 
function show_result(){    //
    //이 함수가 실행되게 되면 컨트롤러에 있는 show_result.do로 맵핑되고, 설문번호 값이 같이 넘어가게 된다.
    location.href="show_result.do?survey_idx=${dto.survey_idx}";
 
}
 
</script>
 
</head>
    <body>
 
    <h2>온라인 설문조사</h2>
 
    <!-- dto에 저장된 문제의 내용 -->
    <h2>${dto.question}</h2
 
 
    <!--여기서 받은 자료들을 post방식으로 컨트롤러에 save_survey.do에 맵핑시킨다.-->
    <form method="post" action="save_survey.do">
 
 
    <!-- radio버튼 타입으로 각 번호마다 문항을 받아와서 출력함 -->
    <!-- radio타입이기때문에 1개만 선택가능 -->
    <input type="radio" name="num" value="1">${dto.ans1}<br
    <input type="radio" name="num" value="2">${dto.ans2}<br>
    <input type="radio" name="num" value="3">${dto.ans3}<br>
    <input type="radio" name="num" value="4">${dto.ans4}<br>
    <br>
    
    <!-- 내가 선택한 문항의 번호가 hidden 타입으로 넘어가야된다. -->
    <input type="hidden" name="survey_idx" value="${dto.survey_idx}">
    
    <!-- 투표버튼을 누르면 넘어가게 된다. -->
    <input type="submit" value="투표">
    
    <!-- 결과확인 버튼을 누르면 자바스크립트 함수인 show_result()가 실행되게 된다. -->
    <input type="button" value="결과 확인" onclick="show_result()">
    
</form>
</body>
</html>
cs



View ( success.jsp )

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 http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
 
<h2>온라인 설문조사</h2>
완료되었습니다.
<a href="<%=request.getContextPath()%>/">Home</a>
<!-- 시작페이지로 이동하는 링크, 스프링 부트가 아니기 때문에 ContextPath()를 붙여줘야 한다.-->
 
</body>
</html>
cs



View ( result.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
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<%@ taglib prefix="c" 
uri="http://java.sun.com/jsp/jstl/core" %>
<h2>설문조사 결과</h2>
문제 : ${map.dto.question}<br><br<!-- 문제 -->
<table border="1">
    <tr align="center">
        <th>문항</th>
        <th>응답수</th>
        <th>응답비율</th>
    </tr>
<c:forEach var="row" items="${map.list}"<!-- 각 항목별 결과의 list를 하나씩 출력해준다. -->
    <tr align="center">
        <td>${row.num}</td<!-- 문항 -->
        <td>${row.sum_num}</td>    <!-- 응답수 -->
        <td>${row.rate}%</td>    <!-- 응답비율 -->
    </tr>
    
</c:forEach>
</table>
<a href="<%=request.getContextPath()%>">Home</a<!-- home로 가는 링크추가 -->
</body>
</html>
cs




:

Spring와 SQL Server 연동

Back-End/Spring 2019. 7. 10. 18:18

Spring와 SQL Server 연동


SQL Server 설치


1) SQL Server 2014 express edition 다운로드 및 설치


2019년 1월 기준 SQL Server의 최신버전은 2017 버전이지만 Windows 7에는 설치가 되지 않으므로


2014 버전을 실습에 사용함


SQL Server 2017 버전은 리눅스에도 설치가 가능함


닷넷 프레임웍 3.5 서비스팩1이 미리 설치되어 있어야 함




SQL 서버 설치


1. SQL 서버 다운로드 링크 = https://www.microsoft.com/ko-kr/download/details.aspx?id=42299




2. ExpressAndTools 64BIT\SQLEXPRWT_x64_KOR.exe 설치




3. 새 SQL Server 독립 실행형 설치 또는 기존 설치에 추가




4. 기본 설치 옵션으로 진행 (계속 다음만 누르다가 아래 사진에 나온 설정만 다시설정)




5. 인증 모드는 혼합 모드로 설치 ( 암호 입력 : 1234 )



6. tcp / ip 원격 접속 설정 (SQL Server 네트워크 구성에서 TCP / IP 클릭) 이따할 예정


6-1 SQL Server 구성 관리자




6-2 SQL Server 네트워크 구성에서 TCP / IP를 클릭해서 아래와 같이 사용하도록 바꾼다.



6-3 옆에 있는 IP주소 탭에서 맨 밑으로 내려가 IPAll에 있는 TCP 포트 번호를 1433 으로 바꾸고, 적용 및 확인 버튼을 누른다.




6-4 SQL서버의 설정을 변경했으므로 서비스에 들어가서 SQL Server를 재시작 해주어야 한다.





참고로 데이터베이스들의 기본 포트번호는 다음과 같다.


Oracle  = 1521


MySQL = 3306


SQL Server = 1433




실행할 때는 SQL Server 2014 Management Studio를 실행하면 된다.




SQL Server 2014 Management Studio를 실행하면 다음 화면이 나오는데 인증방식을 Windows인증 방식을 선택하면 비밀번호를

따로 입력할 필요가 없지만 (이미 윈도우 로그인이 되어있기 때문) 지금은 원격으로 db에 접속을 해야하기때문에 sql server방식으로 접속을 해야한다.



윈도우 방식으로 로그인할 경우




연결을 끊을때는 파일 => 연결끊기 버튼을 누르면 된다.





SQL Server 방식으로 접속하기 (아이디와 비밀번호 입력후 연결버튼 누르기)





  -jdbc 드라이버 다운로드-


  SQL Server의 jdbc 드라이버는 라이센스 문제로 http://mvnrepository.com 에서 배포하지 않음


  따라서 maven 로컬 저장소에 직접 설치를 해야 함


  sqljdbc_6.0.8112.200_kor.exe 파일을 다운로드받아 실행함




 1. https://www.microsoft.com/ko-kr/download/details.aspx?id=11774 접속해서 JDBC 드라이버 다운로드




  




  2.  압축이 해제되고 jre8 디렉토리에 있는 sqljdbc42.jar 파일을 확인할 수 있음




3. 찾기 쉬운 폴더에 jar 파일을 복사함




  -maven 다운로드-

  (maven을 다운로드해서 로컬저장소를 만들예정)


  1. http:.//maven.apache.org/download.cgi에 접속해서 Binary zip archive apache-maven-3.6.0-bin.zip 다운로드



  2. 다운로드 받은 파일의 압축을 풀고 압축을 푼 폴더의 이름을 maven으로 바꾸고 c드라이브에 옮긴다.

      c:/maven에 압축해제




  3. maven 로컬 저장소에 수동으로 설치

  

c:/maven/bin 디렉토리에 sqljdbc42.jar 복사


cmd에서 실행



  cd c:/maven/bin



  mvn install:install-file -Dfile=sqljdbc42.jar -Dpackagin=jar -DgroupId=com.microsoft.sqlserver -DartifactId=sqljdbc4 -Dversion=4.0




위와 같이 코드를 치고, 로컬저장소에 수동으로 추가가 완료되었다면 아래처럼 "BUILD SUCCESS" 라고 출력이 된다.




로컬저장소에 추가한 후에 Spring 프로젝트에서 pom.xml에 라이브러리를 추가해서 사용할 수 있다.



  <dependency>


        <grouId>com.microsoft.sqlserver</groupId>


        <artifactId>sqljdbc4</artifactId>


        <version>4.0</version>


  </dependency>



:

Spring Boot와 MongoDB 연동 실습 (방명록)

Back-End/Spring 2019. 7. 10. 13:37

Spring Boot와 MongoDB 연동 해서 방명록 만들기





 

  

  -방명록 리스트-


  1. home.jsp에 include되어있는 menu.jsp에 있는 방명록 링크를 클릭.


  2. 클릭하면 guestbook.do url이 GuestbookController.java (컨트롤러로 넘어간다)


  3. guestbook.do와 맵핑되는 메소드에서는 다시 guestbook jsp페이지로 이동시킨다.


  4. guestbook.jsp에서는 gbList( ) 자바스크립트함수가 실행되서 컨트롤러에 gbList.do url과 맵핑된다.


  5. gbList.do와 맵핑된 메소드에선 Dao를 호출해 hashmap에 방명록리스트와, 방명록 글갯수를 gb_list로 리턴시킨다.


  6. gb_list에선 방명록에 적힌 게시물수, 이름, 날짜, 이메일, 등을 표시한다. 


  7. 결과적으로 guestbook.jsp (방명록목록) 페이지를 실행하면 gbList.do로 맵핑되어서 방명록 리스트를 가져온다.



  -방명록 글쓰기-


  1. guestbook.jsp 페이지에서 글쓰기 버튼을 누르면 컨트롤러에 gbWrite.to로 맵핑이 된다.


  2. gbWrite.do로 맵핑된 메소드에서는 다시 gb_write.jsp 페이지로 이동시킨다.


  3. gb_write.jsp페이지에서는 작성할 방명록 글 정보를 입력한 후 "확인" 버튼을 누르면 post방식으로 컨트롤러의 gbInsert.do url로 맵핑시킨다.


  4. gbInsert.do로 맵핑된 메소드에서는 mongoDB에 DTO에 담긴 레코드들을 추가해서 목록을 갱신시켜 guestbook.do로 맵핑시킨다.


  5. guestbook.do로 맵핑된 메소드에서는 guestbook.jsp 페이지로 이동시킨다.


  6. guestbook.jsp 페이지로 이동하면 방금 작성한 방명록 글이 추가되어있는것을 확인할 수 있다.


  

  -방명록 글 수정, 삭제-


  1. gb_list.jsp 페이지에서 방명록 작성할때 적은 비밀번호를 적고 "편집" 버튼을 누르면 컨트롤러에 gbEdit.do로 맵핑 시킨다.


  2. gbEdit.do로 맵핑된 메소드에선 hashmap에 _id(키값)을 사용해서 dto에 담긴 값들을 담고, gb_edit.jsp페이지로 이동시키고 map도 같이 보낸다.


  3. gb_edit.jsp 페이지에서는 수정과 삭제를 하려면 키값이 필요하기 때문에 아까 보낸 map에 있는 _id값 (키 값)을 꺼내서 사용한다.


  -글 수정-


  4. 먼저 "수정" 버튼을 누르면 gb_edit() 자바스크립트 함수가 실행되서 컨트롤러에 있는 gbUpdate.do로 맵핑되서 자료를 전송한다.


  5. gbUpdate.do로 맵핑된 메소드에서는 넘겨 받은 자료를 dto객체를 생성해 저장하고, dao에 저장한 후에 guestbook.do로 맵핑된다.


  6. guestbook.do로 맵핑된 메소드에서는 다시 guestbook.jsp 페이지로 이동시킨다.


  7. 이동하면 방금 수정한 방명록 글이 수정되어있는 것을 확인할 수 있다.


  

 -글 삭제-

 

  4. "삭제" 버튼을 누르면 gb_del() 자바스크립트 함수가 실행되서 컨트롤러에 있는 gbDelete.do로 맵핑되서 자료를 전송한다.


  5. gbDelete.do로 맵핑된 메소드에서는 Dao에 articleDelete()메소드에 _id값(키값)을 매개값으로 해서 레코드를 삭제한다.


  6. 레코드를 삭제한 후에 guestbook.do로 맵핑되서 guestbook.jsp 페이지로 다시 이동한다.


  7. 이동하면 방명록의 글이 삭제된것을 확인할 수 있다.








GuestbookDTO.java (방명록 DTO)

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
package com.example.spring04.model.guestbook.dto;
 
import java.util.Date;
 
public class GuestbookDTO {
    
    private String _id;     //키값, id
    private String name;    //이름
    private String email;    //이메일
    private String passwd;    //비밀번호
    private String content;    //내용
    private Date post_date;    //날짜
    //getter,setter,toString()
    
    public String get_id() {
        return _id;
    }
    public void set_id(String _id) {
        this._id = _id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getEmail() {
        return email;
    }
    public void setEmail(String email) {
        this.email = email;
    }
    public String getPasswd() {
        return passwd;
    }
    public void setPasswd(String passwd) {
        this.passwd = passwd;
    }
    public String getContent() {
        return content;
    }
    public void setContent(String content) {
        this.content = content;
    }
    public Date getPost_date() {
        return post_date;
    }
    public void setPost_date(Date post_date) {
        this.post_date = post_date;
    }
    @Override
    public String toString() {
        return "GuestbookDTO [_id=" + _id + ", name=" + name + ", email=" + email + ", passwd=" + passwd + ", content="
                + content + ", post_date=" + post_date + "]";
    }
    
}
 
cs



GuestbookDAO.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package com.example.spring04.model.guestbook.dao;
 
import java.util.List;
 
import com.example.spring04.model.guestbook.dto.GuestbookDTO;
 
public interface GuestbookDAO {
    
    public List<GuestbookDTO> getArticleList(); //방명록 목록
    
    public void articleInsert(GuestbookDTO dto); //글쓰기
    
    public void articleUpdate(GuestbookDTO dto); //수정
    
    public void articleDelete(String _id); //삭제
    
    public GuestbookDTO gbDetail(String _id); //상세화면
    
}
cs



GuestbookDAOImpl.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
package com.example.spring04.model.guestbook.dao;
 
import java.util.Date;
import java.util.List;
 
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Repository;
 
import com.example.spring04.model.guestbook.dto.GuestbookDTO;
@Repository //dao bean
public class GuestbookDAOImpl implements GuestbookDAO {
 
    @Autowired //스프링에서 지원하는 의존성 주입 어노테이션
    MongoTemplate mongoTemplate; //mongodb 실행 객체
    
    String COLLECTION_NAME="guestbook"//컬렉션(테이블) 이름을 guestbook라고 한다.
    
    @Override
    //방명록 리스트를 보여주는 메소드
    public List<GuestbookDTO> getArticleList() {
        Query query=new Query(); //db에 명령내릴것들을 저장하는 객체인 query객체 생성
        query.with(new Sort(Sort.Direction.DESC, "post_date")); //쿼리 객체에 작성날짜의 내림차순으로 저장시킨다.
        List<GuestbookDTO> list=
                (List<GuestbookDTO>)mongoTemplate.find(
                query, GuestbookDTO.class, COLLECTION_NAME);
        //날짜내림차순(query)으로 COLLECTION_NAME테이블에 있는 값들을 찾아서 DTO 타입으로 변환해서 list배열에 넣는다.
        
        //리스트에 있는 글내용을 하나씩 dto에 저장하고 줄간격 변경을 하고, 줄간격변경한 글 내용을 다시 dto에 저장
        for(GuestbookDTO dto : list) { 
            //list에 있는 값들을 dto에 넣고, 줄간격을
            String content = dto.getContent();
            content= content.replace("\r\n""<br>");
            dto.setContent(content);
        }
        
        return list;//리스트 반환
    }
 
    @Override
    //방명록 글쓰기 메소드
    public void articleInsert(GuestbookDTO dto) {
        dto.setPost_date(new Date());    //날짜는 글작성할때 따로 작성해서 글을 쓰는게 아니므로 새로운 객체를 만들어 저장
        mongoTemplate.insert(dto, COLLECTION_NAME); //dto와 COLLECTION_NAME(테이블이름)으로 insert한다.
    }
 
    @Override
    public void articleUpdate(GuestbookDTO dto) {
        // update guestbook set name=?, email=?, content=?
        // where _id=?        
        //new Criteria("필드명").is(값)
        System.out.println(dto);
        Query query = new Query(new Criteria("_id").is(dto.get_id()));
        // 수정할 내용들을 매핑
        Update update=new Update();
        update.set("name", dto.getName());  //dto에 저장된 이름을 update객체에 name라는 이름으로 저장
        update.set("email", dto.getEmail());    //dto에 저장된 이름을 update객체에 email라는 이름으로 저장
        update.set("content", dto.getContent());    //dto에 저장된 글내용을 update객체에 content라는 이름으로 저장
        
        // 1개의 레코드만 수정 (1개의 게시물만 수정한다는 뜻이다. _id값 (키값)을 한개만 받아왔기 때문에)
        mongoTemplate.updateFirst(query, update, COLLECTION_NAME);
        // ( (query=날짜 내림차순으로 정렬시키는 쿼리), (update=이름, 이메일, 글내용), (COLLECTION_NAME=테이블이름) )
    }
 
    @Override
    //게시글을 삭제하는 메소드
    public void articleDelete(String _id) {
        Query query=new Query(new Criteria("_id").is(_id)); 
        //저장된 _id값이 내가 입력한 _id값과 같은지 확인하고, 그 값을 query객체에 저장
        
        mongoTemplate.remove(query, COLLECTION_NAME);
        //remove는 삭제하는 메소드 (_id값 (키값)과 COLLECTION_NAME(테이블이름)으로 자료를 삭제한다.
        
        }
    
    @Override
    //게시물 1개의 상세정보를 보여주는 메소드
    public GuestbookDTO gbDetail(String _id) {
        // findById() 1개의 Document 리턴
        // find() Document 리스트 리턴
        // findById(_id, 자료형클래스, 컬렉션이름)
        return mongoTemplate.findById(_id, GuestbookDTO.class, COLLECTION_NAME);
        //_id(키값)으로 COLLECTION_NAME(테이블)에 저장된 값들을 DTO타입으로 저장해서 리턴한다.
    }
    
}
cs



GuestbookController.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
package com.example.spring04.controller;
 
import java.util.HashMap;
import java.util.List;
import java.util.Map;
 
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;
 
import com.example.spring04.model.guestbook.dao.GuestbookDAO;
import com.example.spring04.model.guestbook.dto.GuestbookDTO;
 
@Controller //컨트롤러 빈 선언
public class GuestbookController {
 
    @Autowired    //스프링객체 의존성 주입 어노테이션
    GuestbookDAO guestbookDao;    //dao를 호출하므로 의존성을 주입
    
    @RequestMapping("/guestbook.do")
    //guestbook.do로 맵핑되어서 다시 guestbook (jsp페이지)로 다시 이동한다.
    public String guestbook() {
        return "guestbook/guestbook";
    }

guestbook.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
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!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" %>
<script>
 
$(function(){ //페이지 로딩이 되면  바로 gbList()함수가 실행
    gbList();
});
 
function gbList(){
    //비동기 방식으로 gbList.do를 호출해서 안에 있는 데이터를 받아옴
    $.ajax({
        url: "${path}/gbList.do",
        
        //데이터가 이동되는게 성공했다면 
        success: function(result){//리스트가 출력된게 result변수로 넘어옴
            $("#gbList").html(result);//id가 gbList인 값안에 result값이 찍히게 된다.
        }
    });
}
</script>
</head>
<body>
<%@ include file="../include/menu.jsp" %>
<h2>방명록</h2>
<input type="button" value="글쓰기" 
    onclick="location.href='${path}/gbWrite.do'">
<div id="gbList"<!-- 이 쪽에 방명록 리스트가 불러와져서 찍히게 된다. --> </div>    
</body>
</html>
cs

    
    @RequestMapping("/gbList.do")
    //guestbook (jsp)페이지가 실행이되면 바로 이 메소드로 맵핑되어서 DAO에 있는 방명록 리스트를 가져온다.
    public ModelAndView gbList() {
        List<GuestbookDTO> items=guestbookDao.getArticleList();
        Map<String,Object> map=new HashMap<>();
        map.put("list", items); //방명록 리스트를 list라는 이름으로 map(해쉬맵)에 저장한다.
        map.put("count", items.size()) ;    //방명록 리스트의 갯수를 count라는 이름으로 map(해쉬맵)에 저장
        return new ModelAndView("guestbook/gb_list""map", map);    //gb_list페이지를 호출하고, map에 담긴 자료를 같이 넘긴다.
    }


gb_list.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
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ include file="../include/header.jsp" %>
게시물수 : ${map.count}건
<c:forEach var="dto" items="${map.list}"
<!-- 개별값은 dto이고, map에 담긴 list -->
 
<form method="post" action="${path}/gbEdit.do"
<!-- post방식으로 컨트롤러에 gbEdit.do로 맵핑한다. -->
 
    <input type="hidden" name="_id" value="${dto._id}">
    <!-- dto에 있는 _id(키값)을 받고, _id라는 이름에 변수로 저장하고, 히든타입으로 넘긴다. -->
    
    <table border="1" style="width:600px;">
        <tr align="center">
        <!-- width는 칸을 %크기로 나눈것 -->
            <td width="20%">이름</td>
            <td width="30%">${dto.name}</td>
            <td width="20%">날짜</td>
            <td width="30%">
            <!-- 날짜에 패턴(타입을 지정) -->
                <fmt:formatDate value="${dto.post_date}"
                    pattern="yyyy-MM-dd HH:mm:ss"/>
            </td>
        </tr>
        <tr>
            <td align="center">이메일</td>
            <td colspan="3">${dto.email}</td>
        </tr>
        <tr>
            <td colspan="4">${dto.content}</td>
        </tr>
        <tr>
                <td colspan="4" align="center">    
                    비밀번호 <input type="password" name="passwd">
                <input type="submit" value="편집">
            </td>
        </tr>
    </table>
</form>
</c:forEach>
cs
    
    @RequestMapping("/gbWrite.do")
    public String gbWrite() {
        return "guestbook/gb_write";
    }

gb_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
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!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" %>
</head>
<body>
<%@ include file="../include/menu.jsp" %>
<h2>글쓰기</h2>
<form name="form1" method="post" action="${path}/gbInsert.do">
<table border="1" width="500px">
    <tr>
        <td>이름</td>
        <td><input name="name"></td>
    </tr>
    <tr>
        <td>이메일</td>
        <td><input name="email"></td>
    </tr>
    <tr>
        <td>비밀번호</td>
        <td><input type="password" name="passwd"></td>
    </tr>
    <tr>
        <td colspan="2">
            <textarea rows="5" cols="55" name="content"></textarea>
        </td>
    </tr>
    <tr>
        <td colspan="2" align="center">
            <input type="submit" value="확인">
            <input type="reset" value="취소">
        </td>
    </tr>
</table>
</form>
</body>
</html>
cs
    
    @RequestMapping("/gbInsert.do")
    public String gbInsert(@ModelAttribute GuestbookDTO dto) {
        //mongodb에 Document(레코드) 추가
        guestbookDao.articleInsert(dto);
        //페이지 이동(목록 갱신)
        return "redirect:/guestbook.do";
    }
    
    @RequestMapping("/gbEdit.do")
    public ModelAndView gbEdit(String _id) {
        // _id : mongodb의 Document(레코드)의 식별자
        GuestbookDTO dto=guestbookDao.gbDetail(_id);
        Map<String,Object> map=new HashMap<>();
        map.put("dto", dto);
        return new ModelAndView("guestbook/gb_edit","map",map);
    }


gb_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
56
57
58
59
60
61
62
63
64
65
66
67
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!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" %>
<script>
//컨트롤러에 있는 gbUpdate.do로 맵핑되어서 자료를 전송한다.
function gb_edit(){
    document.form1.action="${path}/gbUpdate.do";
    document.form1.submit();
}
 
//컨트롤러에 있는 gbDelete.do로 맵핑되어서 자료를 전달한다.
function gb_del(){
    if(confirm("삭제하시겠습니까?")){
        document.form1.action="${path}/gbDelete.do";
        document.form1.submit();
    }
}
 
</script>
</head>
<body>
<%@ include file="../include/menu.jsp" %>
<form method="post" name="form1">
<table border="1" width="500px">
    <tr>
    <!-- map에 저장된 dto값들을 하나씩 출력해서 넣어준다. -->
        <td>이름</td>
        <td><input name="name" value="${map.dto.name}"></td>
    </tr>
    <tr>
        <td>이메일</td>
        <td><input name="email" value="${map.dto.email}"></td>
    </tr>
    <tr>
        <td>비밀번호</td>
        <td><input type="password" name="passwd"></td>
    </tr>
    <tr>
        <td colspan="2">
            <textarea rows="5" cols="55" name="content">${map.dto.content}</textarea>
              
        </td>
    </tr>
    <tr>
        <td colspan="2">
        <!-- 수정과 삭제를 하기위해서는 키값이 필요하다. 그렇기 때문에 히든타입으로 (_id) 받아온다. -->
            <input type="hidden" name="_id" value="${map.dto._id}">
            
            <input type="button" value="수정" onclick="gb_edit()"
            <!-- 수정버튼을 누르면 위쪽에 있는 자바스크립트 함수 gb_edit()가 실행된다.-->
            
            <input type="button" value="삭제" onclick="gb_del()">
            <!-- 삭제버튼을 누르면 위쪽에 있는 자바스크립트 함수 gb_del()가 실행된다.-->
            
            <input type="button" value="목록"
                onclick="location.href='${path}/guestbook.do';">
                    </td>
                </tr>
            </table>
        </form>
    </body>
</html>
cs

    
    @RequestMapping("/gbUpdate.do")
    //public String gbUpdate(@ModelAttribute GuestbookDTO dto) {
    public String gbUpdate(@RequestParam String _id
            , @RequestParam String name
            , @RequestParam String email
            , @RequestParam String content
            , @RequestParam String passwd) {        
        //System.out.println(dto);
        //Document(레코드) 수정
        GuestbookDTO dto=new GuestbookDTO();
        dto.set_id(_id);
        dto.setName(name);
        dto.setEmail(email);
        dto.setContent(content);
        dto.setPasswd(passwd);
        
        guestbookDao.articleUpdate(dto);
        //목록 페이지로 이동
        return "redirect:/guestbook.do";
    }
    
    @RequestMapping("/gbDelete.do")
    public String gbDelete(String _id) {
        //Document(레코드) 삭제
        guestbookDao.articleDelete(_id);
        //목록 페이지로 이동
        return "redirect:/guestbook.do";
    }
}

cs




  guestbook.jsp 에서  글쓰기 버튼을 만들어서 클릭하면 gbWrite( )함수가 호출되고, 그 함수에서 컨트롤러의 gbWrite.do로 맵핑되고,


  컨트롤러에서는 gbWrite.do로 맵핑된 메소드에서 gb_write (방명록 글쓰기) 페이지로 이동하게 리턴시키고,  


  방명록을 작성 (이름, 이메일, 비밀번호,본문내용)을 입력하고 "확인" 버튼을 누르면 javascript check( ) 함수가 호출되서, 


  id가 form1인 태그를 가져와서 컨트롤러에 gbInsert.do로 맵핑시킨다.


  gdInsert.do로 가면 form에 붙여놨던 자료들이 넘어가게 되고, 저장된 이름이 null이면 


  (그러니까 이름을 입력하지 않고 확인버튼을 누르면) gbWritd.do로 맵핑시킨다.







:

Spring Boot와 MongoDB 연동 실습 (한줄메모장)

Back-End/Spring 2019. 7. 9. 17:27

한줄메모장 만들기


MongoDB는 테이블을 사전에 만들 필요가없고, 코딩에 의해 테이블이 즉각적으로 생겨나고 자료가 삽입된다.


비정형 데이터를 넣는것에 적합한 DB이다.



 

  한줄메모장 구조



  -글목록-


  1. home.jsp에 include된 menu.jsp 페이지에 있는 "메모장" 버튼을 누르면 MemoController.java에 있는 memo.do메소드로 맵핑된다.


  2. 맵핑된 메소드에서 memo.jsp 페이지로 이동시킨다.


  3. memo.jsp 페이지가 호출될때 가장먼저 memo_list() 함수가 호출되고, ajax방식이고, 컨트롤러에 memo_list.do와 맵핑되는데 데이터만

     넘어가고 화면은 바뀌지 않는다.


  4. memo_list.do와 맵핑된 컨트롤러의 메소드에서는 서비스에서 메모목록을 가져와 hashmap에 저장하고, memo_list.jsp 페이지로

     이동시키고, 아까 map변수에 담은 list도 같이 넘겨준다.


  5. memo_list.jsp 페이지에서는 넘겨받은 map에 있는 게시글번호, 작성자 이름, 작성글내용, 작성날짜를 출력한다.

  


  -글쓰기-


  1. memo.jsp 페이지에서 "이름" 과 "메모" 를 작성한 후에 "확인" 버튼을 누르면 해당되는 id값 (btnWrite)가 넘어가서 id값에 맞는 

     자바스크립트 함수가 실행되고, 이 함수는  memo_insert()함수를 호출한다.


  2. memo_insert() 함수에서 작성자의 이름과 메모를 각각 변수에 담고, ajax방식으로 페이지를 안바꾸고 데이터만 post방식으로

     컨트롤러에 memo_insert.do로 맵핑시킨다.


  3. memo_insert.do에 맵핑된 메소드에서는 서비스를 호출해서 dto값을 담고 memo.do로 다시 맵핑시킨다.


  4. memo.do로 맵핑된 메소드에서는 다시 memo.jsp 페이지로 이동시킨다.


  5. 아까 memo_inset() 함수가 정상적으로 실행되서 자료가 전달되었으므로, success문 하위에 있는 memo_list()함수가 실행된다.


  6. memo_list()함수가 실행되면 ajax방식으로 컨트롤러에 memo_list.do와 맵핑되고, 거기에서 list를 map로 받아온다.


  7. memo_list()함수에서 자료 전달이 성공적으로 됬으므로 success문을 실행해서 컨트롤러에서 받아온 map값을 result 변수에 저장하고,

     id가 #memoList인 태그에 컨트롤러로부터 넘겨받은 map를 출력시키면 메모글이 추가된다.



  -글삭제-


  1. memo_view 페이지에서 "삭제" 버튼을 누르면 id값인 btnDelete가 위쪽 자바스크립트 함수와 맵핑되어서 자바스크립트 함수에서

     컨트롤러에 있는 memo_delete.do로 맵핑되면서 자료를 넘겨준다.


  2. memo_delete.do로 맵핑된 메소드에서 서비스에 _id(키값)을 매개변수로 넘겨서 레코드를 삭제하고 memo.do로 리턴시킨다.


  3. memo.do로 맵핑된 메소드에선 memo.jsp 페이지로 이동시킨다. 


  4. memo.jsp 가 호출되었으므로 memo_list() 함수가 호출되어서 ajax방식으로 컨트롤러에 있는 memo_list.do로 맵핑된다.


  5. memo_list.do에선 아까 갱신(삭제한) 리스트를 다시 map에 담아서 memo_list.jsp 페이지로 리턴한다. (map)와 함께


  6. memo_list.jsp 에선 map에 있는 자료를 차례로 출력하면 아까 삭제한 글을 제외하고 리스트로 출력되게 된다.



  -글수정-


  1. memo_view 페이지에서 자료를 수정하고 "수정" 버튼을 누르면 id값인 btnUpdate가 위쪽 자바스크립트 함수와 

     맵핑되어서 자바스크립트 함수에서컨트롤러에 있는 memo_update.do로 맵핑된다.


  2. memo_update.do와 맵핑된 메소드에선 서비스를 호출해서 memoUpdate메소드에 dto에 담긴값들을 매개변수로 담고, 

     memo.do로 리턴한다.


  3. memo.do와 맵핑된 메소드에선 다시 memo.jsp 페이지로 이동시킨다.


  4. memo.jsp 페이지가 실행되었으므로 memo_list()함수가 실행된다.


  5. memo_list()함수에서는 ajax방식으로 memo_list.do와 맵핑되서 화면은 바뀌지 않고 데이터만 컨트롤러로 넘긴다.


  6. memo_list.do와 맵핑된 컨트롤러에 있는 메소드에서는 서비스를 호출해 list를 hashmap에 저장하고, 

     memo_list.jsp 페이지로 자료를 넘기고, 페이지를 이동시킨다.  


  7. memo.jsp 페이지에서는 ajax방식으로 자료를 보내는데에 성공했으므로 success구문이 실행되서 

     컨트롤러가 받아온 값을 result변수에 저장하고, id가 #memoList인 태그에 넘어온 값을 출력시킨다.

     (그러니까 memo.jsp페이지에서 메모리스트(memo_list)를 보여줌


  



MemoDTO.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
package com.example.spring04.model.memo.dto;
 
import java.util.Date;
 
public class MemoDTO {
    
    private String _id; //id는 pk이므로 _id로 하여야한다.
    private String writer;    //작성자
    private String memo;    //메모내용
    private Date post_date;    //날짜
    
    //getter/setter,toString()
    
    public String get_id() {
        return _id;
    }
    public void set_id(String _id) {
        this._id = _id;
    }
    public String getWriter() {
        return writer;
    }
    public void setWriter(String writer) {
        this.writer = writer;
    }
    public String getMemo() {
        return memo;
    }
    public void setMemo(String memo) {
        this.memo = memo;
    }
    public Date getPost_date() {
        return post_date;
    }
    public void setPost_date(Date post_date) {
        this.post_date = post_date;
    }
    public MemoDTO(String _id, String writer, String memo, Date post_date) {
        super();
        this._id = _id;
        this.writer = writer;
        this.memo = memo;
        this.post_date = post_date;
    }
    
}
 
cs



MemoDAO.java 생성

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package com.example.spring04.model.memo.dao;
 
import java.util.List;
 
import com.example.spring04.model.memo.dto.MemoDTO;
 
public interface MemoDAO {
    List<MemoDTO> getMemoList();    //목록보기
    void memoInsert(MemoDTO dto);    //글쓰기
    MemoDTO memoDetail(String _id);    //상세화면
    void memoUpdate(MemoDTO dto);    //글수정
    void memoDelete(String _id);    //글삭제
}
 
cs



MemoDAOImpl.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
package com.example.spring04.model.memo.dao;
 
import java.util.Date;
import java.util.List;
 
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Repository;
 
import com.example.spring04.model.memo.dto.MemoDTO;
 
@Repository //DAO 사용 어노테이션 선언
public class MemoDAOImpl implements MemoDAO {
 
    @Autowired    //MongoDB사용을 하기위해 의존성을 주입한다.
    MongoTemplate mongoTemplate;
    String COLLECTION_NAME="memo"//컬렉션(테이블) 이름을 "memo"라고 한다,

    
    @Override
    public List<MemoDTO> getMemoList() {
        //목록을 뽑을때 사용하는 클래스 (query)
        Query query=new Query();
        query.with(new Sort(Sort.Direction.DESC, "post_date")); //날짜기준 내림차순 정렬
        return (List<MemoDTO>)mongoTemplate.find(//memo테이블에서 날짜기준으로 내림차순 정렬시킨 값을 DTO타입으로 저장해 리스트를 만들어 리턴하라는 의미이다.
                query, MemoDTO.class, COLLECTION_NAME);
    }
 
    @Override
    public void memoInsert(MemoDTO dto) {//저장할때 날짜를 따로 입력해서 저장하지 않기 때문에  
        dto.setPost_date(new Date()); 
                                                    
        //java.util.Date
        // insert( 추가할객체, 컬렉션이름 )
        mongoTemplate.insert(dto, COLLECTION_NAME); //코드로 날짜를 집어넣고 insert를 하면 된다.
    }
 
    @Override
    public MemoDTO memoDetail(String _id) {
        //id에 해당하는 값 (레코드) 1개를 찾을 경우에는 findById(_id, 클래스, 테이블이름) 사용
        return mongoTemplate.findById(
                _id, MemoDTO.class, COLLECTION_NAME);
        //id에 해당되는 자료를 COLLECTION_NAME테이블에서 가져와서 DTO에 저장
    }
 
    @Override
    public void memoUpdate(MemoDTO dto) {
        // update 테이블 set 필드=값, 필드=값 where 필드=값
        // where 조건
        Query query=new Query(
                new Criteria("_id").is(dto.get_id()));
        //테이블에 있는 id와 내가적은 id가 같을경우에 글을 수정할 수 있다.
        //수정할 내용
        Update update=new Update();
        update.set("writer", dto.getWriter());
        update.set("memo", dto.getMemo());
        // upsert : update or insert
        //없으면 추가하고, 있으면 수정한다는 의미이다.
        mongoTemplate.upsert(
                query, update, MemoDTO.class, COLLECTION_NAME);
    }
 
    @Override
    public void memoDelete(String _id) {
        Query query=new Query(new Criteria("_id").is(_id)); //저장되있는 아이디가 내가 입력한 아이디와 같을경우에
        mongoTemplate.remove(query, COLLECTION_NAME);        //테이블에 있는 쿼리를 삭제함
    }
 
}
 

cs



MemoService.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package com.example.spring04.service.memo;
 
import java.util.List;
 
import com.example.spring04.model.memo.dto.MemoDTO;
 
public interface MemoService {
    
    List<MemoDTO> getMemoList();    //메모 목록
    void memoInsert(MemoDTO dto);    //메모 저장
    MemoDTO memoDetail(String _id);    //메모 상세 내용 보기
    void memoUpdate(MemoDTO dto);    //메모 수정
    void memoDelete(String _id);    //메모 삭제
}
 
cs



MemoServiceImpl.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
package com.example.spring04.service.memo;
 
import java.util.List;
 
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
 
import com.example.spring04.model.memo.dao.MemoDAO;
import com.example.spring04.model.memo.dto.MemoDTO;
 
@Service    //서비스 어노테이션
public class MemoServiceImpl implements MemoService {
 
    @Autowired //스프링프레임워크 의존성 주입, dao를 호출하기위해 의존성을 주입
    MemoDAO memoDao;
 
    
    
    @Override
    public List<MemoDTO> getMemoList() {    //메모 목록 리턴    
        return memoDao.getMemoList();
    }
 
    @Override
    public void memoInsert(MemoDTO dto) {    
        memoDao.memoInsert(dto);
    }
 
    @Override
    public MemoDTO memoDetail(String _id) {
        return memoDao.memoDetail(_id); 
    }
 
    @Override
    public void memoUpdate(MemoDTO dto) {
        memoDao.memoUpdate(dto); 
    }
 
    @Override
    public void memoDelete(String _id) {
        memoDao.memoDelete(_id); 
    }
 
}
 
cs



menu.jsp에서 메모장 링크를 눌렀을때, memo.do로 맵핑되서 메모 목록을 얻어서 화면에 출력시킬 예정



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
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="c" 
uri="http://java.sun.com/jsp/jstl/core" %>
 
<!-- HOME, 메모장, 방명록페이지로 가는 링크를 추가 -->
<a href="${path}/">Home</a> | 
<a href="${path}/memo.do">메모장</a> | 
<a href="${path}/guestbook.do">방명록</a> | 
<div style="text-align:right;">
    
    <c:choose>
    <!-- 세션에 저장된 유저의 아이디가 NULL이면 로그인페이지로 이동 -->
    <c:when test="${sessionScope.userid == null }">
    
    <!-- 로그인 페이지로 이동하는 링크 -->
    <a href="${path}/member/login.do">로그인</a>
    </c:when>
    
    <c:otherwise>
        <!-- 세션에 저장된 유저의 아이디가 NULL이 아니라면 로그인 중이라는 메시지를 출력한다. -->
        ${sessionScope.name}님이 로그인중입니다.
        
        <!-- 로그인중이므로 로그아웃 할 수 있는 링크를 추가한다. -->
        <a href="${path}/member/logout.do">로그아웃</a>
        
    </c:otherwise>
</c:choose>    
</div>  
<hr>
cs



MemoController.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
package com.example.spring04.controller;
 
import java.util.HashMap;
import java.util.List;
import java.util.Map;
 
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
 
import com.example.spring04.model.memo.dto.MemoDTO;
import com.example.spring04.service.memo.MemoService;
 
@Controller //컨트롤러 빈 선언
public class MemoController {
 
    @Autowired // @Inject, 서비스를 호출하기위해 의존성을 주입
    MemoService memoService;
    
    @RequestMapping("/memo.do")
    public String memo() {
        return "memo/memo"//memo디렉토리에 memo jsp파일로 가서 목록을 다시 얻어온다.
    }
    
    
    @RequestMapping("/memo_list.do"//게시물 리스트
    public ModelAndView memo_list() {
        Map<String,Object> map=new HashMap<>();
        List<MemoDTO> list=memoService.getMemoList(); //서비스에서 메모목록을 가져온다.
        map.put("items", list); //값이 여러개기때문에 hashmap로 담아서 ModelAndView로 넘기고, 거기에서 memo_list jsp페이지에 "memo"라는 변수명으로 보내 출력시킨다.
        return new ModelAndView("memo/memo_list""map", map);
    }
    
    @RequestMapping("/memo_insert.do"//게시물 삽입
    public String memo_insert(@ModelAttribute MemoDTO dto) {
        memoService.memoInsert(dto);
        return "redirect:/memo.do";
    }
    
    @RequestMapping("/memo_view.do"
    public ModelAndView memo_view(String _id) {
        MemoDTO dto=memoService.memoDetail(_id);
        return new ModelAndView("memo/memo_view""dto", dto);
    }
    
    @RequestMapping("/memo_update.do")
    public String memo_update(@ModelAttribute MemoDTO dto) {
        memoService.memoUpdate(dto);
        return "redirect:/memo.do";
    }
    
    @RequestMapping("/memo_delete.do")
    public String memo_delete(String _id) {
        memoService.memoDelete(_id);
        return "redirect:/memo.do";
    }
}
cs



View 파일들


memo.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
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!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" %>
<script>
//이 페이지가 호출되었을때 memo_list()가 맨처음 실행
$(function(){
    memo_list();
    
    //메모를 쓰고 난다음 확인버튼을 누르면 밑에있는 코드에 id값 :btnWrite가 이 태그로 맵핑되고, memo_insert()함수가 실행된다.
    $("#btnWrite").click(function(){
        memo_insert();
    });
});
 
function memo_insert(){
    var writer=$("#writer").val(); // 메모를 작성한 작성자의 이름이 writer변수에 담긴다.
    var memo=$("#memo").val();        // 작성한 메모가 memo변수에 저장된다.
    
    $.ajax({                                //ajax방식은 페이지가 바뀌지 않고 데이터만 주고 받을 수 있는 방식
        type: "post",                        //post방식으로 넘김
        data: {"writer":writer, "memo":memo},//각각 값들을 저장함
        url: "${path}/memo_insert.do",    //memo_insert.do (컨트롤러로) 맵핑됨
        
        success: function(){ //위의 구문이 성공했을시에 실행되는 함수
            memo_list(); //목록 갱신
            $("#writer").val(""); //writer에 value값에 ""(공백) 값을 넣는다.
            $("#memo").val("");        //memo에 value값에 ""(공백) 값을 넣는다.
        }
    });
}
//맨 처음 실행되는 함수 ajax방식으로 실행되고, memo_list.do와 맵핑 (다시 데이터만 컨트롤러로 넘어감, 화면은 안바뀜)
function memo_list(){
    
    //ajax방식은 화면이 안바뀌고 백그라운드에서만 실행되는것.
    $.ajax({
        url: "${path}/memo_list.do",
        success: function(result){ //컨트롤러가 받아온 값을 result변수에 저장하고, id가 #memoList인 태그에 넘어온값을 출력시킬 예정
            $("#memoList").html(result);
        }
    });
}
function memo_view(num){
    // memo_view.do?_id=5
    location.href="${path}/memo_view.do?_id="+num;
}
</script>
</head>
<body>
<%@ include file="../include/menu.jsp" %>
<h2>한줄메모장</h2>
 
이름 : <input id="writer">
메모 : <input id="memo" size="50">
<input type="button" value="확인" id="btnWrite">
<div id="memoList"></div>
</body>
</html>
cs



memo_list.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
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="c" 
uri="http://java.sun.com/jsp/jstl/core" %>
<%@ taglib prefix="fmt" 
uri="http://java.sun.com/jsp/jstl/fmt" %>
 
<table border="1" width="700px">
    <tr>
        <th>No</th>
        <th>이름</th>
        <th>메모</th>
        <th>날짜</th>
    </tr>
<c:forEach var="row" items="${map.items}" varStatus="status"<!-- varStatus는 변수명을 붙인것 -->
                <!-- 컨트롤러에서 보낸 map의 items안에 있는 값들을 하나씩 출력 -->
    <tr>
        <td>${status.count}</td
        <!-- 원래 {row._id}가 키값인데 이렇게 쓰면 숫자 뒤에 소수점이 붙어서 나오고, status를 쓰면 중간에 값이 빠질일이 없이 제대로 출력된다.-->
        <!-- index 0부터, count 1부터이기 때문에 count를 사용해서 소수점을 제외하고 출력시킨다.-->
        
        <td>${row.writer}</td>
        <!--작성자이름을 호출한다.-->
        
        <td>
            <a href="#" onclick="memo_view('${row._id}')">${row.memo}</a>
            <!-- _id가 키값이기 때문에 id를 넘겨서  메모내용으로 넘어간다.-->
        </td>
        <td>
        <!-- 날짜가 나오는 형식을 지정하기 위해 formatDate태그와 패턴을 사용한다. -->
        <fmt:formatDate value="${row.post_date}" 
                pattern="yyyy-MM-dd HH:mm:ss" /></td>
    </tr>
</c:forEach>    
</table>
cs



memo_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
38
39
40
41
42
43
44
45
46
47
48
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!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" %>
<script>
$(function(){
    //수정버튼을 클릭하면 실행되는 함수, 밑에 코드에서 맵핑되어서
    //컨트롤러의 memo_update.do url로 맵핑시킨다.
    $("#btnUpdate").click(function(){ 
        document.form1.action="${path}/memo_update.do";
        document.form1.submit();
    });
    
    //삭제버튼을 클릭하면 실행되는 함수, 밑에 코드에서 맵핑되어서
    //컨트롤러에 memo_delete.do url로 맵핑시킨다.
    $("#btnDelete").click(function(){
        if(confirm("삭제하시겠습니까?")){
            document.form1.action="${path}/memo_delete.do";
            document.form1.submit();
        }
    });
});
</script>
</head>
<body>
<%@ include file="../include/menu.jsp" %>
<h2>메모장</h2>
 
<form name="form1" method="post"<!--키값이 id이기 때문에 _id를 dto에서 받아서 히든타입으로 자료를 넘겨준다. -->
<input type="hidden" name="_id" value="${dto._id}">
 
이름 <input name="writer" value="${dto.writer}"><br<!-- dto에 저장된 작성자이름 출력 -->
메모 <input name="memo" value="${dto.memo}" size="50"><br><!-- dto에 저장된 메모 출력 -->
 
<input type="button" value="수정" id="btnUpdate"<!-- 수정버튼을 누르면 id값이 위쪽에 있는 자바스크립트 함수에  맵핑되서 자바스크립트문에서 컨트롤러로 이동시킴-->
 
<input type="button" value="삭제" id="btnDelete"<!-- 삭제버튼을 누르면 id값이 위쪽에 있는 자바스크립트 함수에  맵핑되서 자바스크립트문에서 컨트롤러로 이동시킴-->
 
<input type="button" value="목록" id="btnList" onclick="location.href='${path}/memo.do'">
<!-- 목록 버튼을 누르면 id값인 btnList가 컨트롤러로 맵핑됨 (memo.do URL로) -->
 
</form>
</body>
</html>
cs



mongo DB에서 서버를 실행하고, 프로젝트를 run해서 메모장에 값들을 집어넣어본후에 mongoDB에서 자료를 


검색해보면 _id값이 고유번호인 uuid로 나오는 것을 확인해볼 수 있다.


(왜냐하면 글번호는 작성자가 집어넣는게 아니기 때문이고, _id값을 따로 정해주지 


않았기때문에 서버에서 임의적으로 정해서출력된 값이기 때문이다.)





:

Spring 어노테이션 정리

Back-End/Spring 2019. 7. 8. 21:20

 - 스프링 어노테이션 정리 -


 어노테이션 이름

 설명 

 @Controller

 컨트롤러 

 @RestController

 컨트롤러 (json을 리턴할 경우)

 @Service

 서비스

 @Repository

 dao bean 

 @Component

 범용적인 bean (서비스나 dao 등에 다 붙일수 있다)

 @Inject

 의존관계 주입 (자바에서 원래 사용했음)

 @AutoWired

 의존관계 주입 (스프링에서 지원)

 @RequestParam

 get / post 방식으로 전달되는 매개변수 (개별변수) 

 @ModelAttribute

 get / post 방식으로 전달되는 매개변수 (클래스 타입)

 @RequestBody

 json 형식의 입력 변수 

 @ResponseBody 

 json 형식의 출력값 

 @PathVariable

 url에 포함된 변수


: