요번에는 Mariadb 설치 후 외부접속을 설정하는 방법을 알아보겠습니다.

 

일단 전 가상머신을 사용하며 ubuntu 18.04를 설치했습니다.

 

Centos도 많이 사용하긴 하지만 전 그냥 지금 ios가 있던 우분투를 사용합니다.

 

설치는 알아서 하시면 됩니다.

 

MariaDB는 무료니까 그리고 Mysql과 같은 환경(?)이니까 사용하겠습니다.

 

Mysql사용자도 활용 가능합니다.

 

sudo apt-get install -y mariadb-server

우분투(데비안 계열)의 경우 위와 같은 명령어로 설치가 가능합니다. 

 

페도라 계열에선 yum이란 명령어를 쓰죠

 

MariaDB설치 후 mysql 명령어가 생겼다면 설치가 완료된것입니다.

 

일단 root의 비밀번호를 설정해주겠습니다.

 

sudo mysqladmin password 비밀번호

 

sudo 명령어 없이는 root 비밀번호를 입력하여도 db에 접속이 안됩니다.

 

myslq에 접속해줍니다 sudo  명령어로 접속시 가능합니다.

select user, host, password, plugin from mysql.user;

위와 같은 화면이 나오면 됩니다. 만약에  password가 빈칸이라면 비밀번호 설정이 안된겁니다.

우리가 원하는 비밀번호로  root 사용자를 사용하려면 plugin이 mysql_native_password로 변경되어야합니다.

 

UPDATE mysql.user SET plugin='mysql_native_password', password=PASSWORD('1111') WHERE user='root';

위의 명령어를 실행하면 됩니다. 위는 plugin과 password를 변경하는 sql문입니다.

설정비밀번호는 1111위치에 원하는 비밀번호로 변경하시면 됩니다.

 

이제 바뀐 부분을 적용시켜 줘야 합니다.

flush privileges;

위의 명령어로 바뀐 부분을 적용해줍니다.

이제  sudo  명령어 없이 mysql접속이 가능한지 확인하시면 됩니다.

전 잘 됩니다. 다들 확인 해보시면됩니다.

 


show variables like 'c%';

위의 명령어로 MariaDB의 기본 Character set을 확인 가능합니다.

 utf8mb4로 세팅될걸 보니 더 수정할건 없을것 같습니다.

UTF-8과 utf8mb4의 다른점은 찾아보시면 됩니다.

utf8mb4는 이모지(이모티콘)를 지원하며 utf8은 에러가 난다네요.


이제 드디어 외부에서 접속이 가능한 아이디를 만들어보겠습니다.

일단 외부에서 접속 가능한 아이디를 만들어줍니다.

 

INSERT INTO mysql.user (user,host,password) VALUES ('root','%',PASSWORD('1111'));
create user 'root'@'%' identified by '1111';

위의 query문중 하나만 입력하시면 됩니다.

user는 접속 id입니다

host는 접속할 ip입니다. %로 설정시 모든 아이피 접속이 가능합니다. 특정 ip, c Class로 사용이 가능하다고 합니다.

password는 비밀번호 입니다. create user 사용시 위의 query와 비교하시면 됩니다.

 

이제 권한을 줘야겠죠 권한을 주겠습니다.

GRANT ALL PRIVILEGES on *.* to 'root'@'%';
ALL

[SELECT, INSERT, UPDATE, DELETE] 4개중 원하는 권한 설정 가능

모든 권한 ALL로 입력

*.* DB이름 * Table이름
root 사용자 id
% 접속 주소

위의 설명을 참고하시면 됩니다.

 

FLUSH PRIVILEGES;

유저 및 권한 설정 후에 반드시 적용을 해야 적용이 됩니다. 위처럼 입력하시면 됩니다.

 

모든 권한을 있는 계정을 외부에 공계하는건 위험하겠죠?

위의 내용을 참고하여 디비 생성 후 각 권한에 맞는 사용자 계정을 주시면 됩니다.


이제 원격에서 접속을 해보겠습니다!

 

접속 하려는데 오류가 났습니다. conf파일을 뒤져보다 문제를 찾았습니다...

 

sudo grep -ir 'bind-address' /etc/mysql/

위의 명령어는 원하는 텍스트가 있는 문서를 찾는 명령어입니다.

 

위와 같이 bind-address라는 config가 있네요 이부분을 주석해주셔야 외부에서 접속이 가능합니다.

 

위와 같이 bind-address의 내용을 주석처리 하고 저장 후 서비스를 재시작 해줍니다.

 

이제 접속을 해봅시다. 혹시나 그래도 안된다면

plugin이 빈값이라면 위에서 설정해줬던 plugin에 mysql_native_password를 넣어줍시다.

 

update mysql.user set plugin='mysql_native_password' where user='root';

위에 query문을 입력하면 user가 root인 row에 plugin을 mysql_natevie_password로 전체 변경합니다.

 

 

다시 확인!

위와 같이 외부에서 접속했을때 정상 동작합니다. 굳 

 

(제가 쓰는 툴은 하이디sql입니다.)


WRITTEN BY
아가루이

,

이번엔 일단 DB연동을 해보려 합니다.

 

MariaDB로 연동을 할것이며 기본 세팅은 아래 링크를 확인해주세요

DB/MariaDB] - MariaDB(Mysql) 설치 후 설정 및 외부 접속


JDBC 설정 및 MyBatis를 설정해주겠습니다.

 

https://mvnrepository.com/

 

Maven Repository: Search/Browse/Explore

Colesico framework data bean validation assistant and simple dsl validator Last Release on Feb 12, 2020

mvnrepository.com

위의 홈페이지에서 Maven 혹은 Gadle의 추가 방법을 확인하셔서 추가하시면 됩니다. 찾는 라이브러리 버전을 확인할 수 있습니다.

 

pom.xml파일을 열어줍니다.

위와 같은 화면이 보입니다. 아래 맨 아래 pox.xml을 누르면 파일 자체를 수정가능하게 열립니다. 

전에 한글 경로 문제로 추가했던 적이 있죠.

Dependencies에서도 추가가 가능합니다.

 

<!-- spring관련 jdbc와 test 라이브러리 (지금 사용중인 스프링 버전 사용) -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>${org.springframework-version}</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-test</artifactId>
    <version>${org.springframework-version}</version>
</dependency>

<!-- mybatis와 스프링에서 mybatis 사용 라이브러리 -->
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.4</version>
</dependency>
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis-spring</artifactId>
    <version>2.0.3</version>
</dependency>

<!-- Database Connection Pool관리 라이브러리  -->
<dependency>
  <groupId>org.apache.commons</groupId>
  <artifactId>commons-dbcp2</artifactId>
  <version>2.6.0</version>
</dependency>

<!-- mariaDB와 연결 라이브러리 -->
<dependency>
    <groupId>org.mariadb.jdbc</groupId>
    <artifactId>mariadb-java-client</artifactId>
    <version>2.5.4</version>
</dependency>

위의 내용을 dependencies에 추가하시면 됩니다.

프로젝트 선택 후 ALT + F5를 눌러 프로젝트를 업데이트 해줍니다.

이제 Maven에는 적용이 됐습니다.

 

src -> main -> webapp -> WEB-INF -> spring에서 root-context.xml파일을 열어 Namespaces를 선택하고 위와 같이 선택해줍니다.

 

<!-- DB연동 부분 (JDBC 관련 설정)  -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    <property name="driverClassName" value="org.mariadb.jdbc.Driver" />
    <property name="url" value="jdbc:mariadb://172.30.1.9:3306/demo_db" />
    <property name="username" value="demo_db_admin" />
    <property name="password" value="qwer1234!" />
</bean>

<!-- mapper 등록하여 dataSource를 통한 연결 (mybatis-spring 관련 연결 부분) -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <property name="mapperLocations" value="classpath:/mappers/**/*Mapper.xml" />
</bean>

<!-- sqlSessionFactory에서 열린 session을 관리함  -->
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
    <constructor-arg index="0" ref="sqlSessionFactory" />
</bean>

위의 내용을 복붙해주시면 됩니다.

주석을 보시면서 이해하시길...

위에서 url, username, password mapperLocations 4부분만 해당 프로젝트에 맞춰주시면 됩니다.

 

위의 db관련 생성 query문은 더보기를 눌러주세요.

CREATE DATABASE IF NOT EXISTS demo_db;
INSERT INTO mysql.user (user,host,password,plugin) 
SELECT * FROM (SELECT 'demo_db_admin', '%', PASSWORD('qwer1234!'),'mysql_native_password') AS tmp WHERE NOT EXISTS (SELECT user FROM mysql.user WHERE user='demo_db_admin') LIMIT 1;
GRANT ALL PRIVILEGES ON demo_db.* to 'demo_db_admin'@'%' IDENTIFIED BY 'qwer1234!';
flush PRIVILEGES;

 

mapperLocations에서 해당 경로는 src/main/resources에 mappers폴더를 만들고 그 폴더에 앞으로 사용할 Mapper를 만들어주시면 됩니다.

 

이제 login관련 테이블을 만들어보겠습니다.

제가 했던거 기반으로 기본적인 내용으로만 생성하였습니다.

또한 기본으로 사용하던 id = test, password = 1111

원하는 Column이나 이런건 알아서 추가하시면 됩니다. 생성문이 궁금하시면 더보기 버튼 클릭하세요~

더보기
CREATE TABLE `USER_LOGIN_INFO_TB` (
	`idx` INT NOT NULL AUTO_INCREMENT,
	`id` VARCHAR(15) NOT NULL,
	`password` VARCHAR(15) NOT NULL,
	`session_id` VARCHAR(50) NULL DEFAULT '',
	PRIMARY KEY (`idx`)
)
COLLATE='utf8mb4_general_ci';
INSERT INTO `demo_db`.`USER_LOGIN_INFO_TB` (`id`, `password`) VALUES ('test', '1111');

 

다시 돌아와

Mapper는 *Mapper로 이름을 만들어줘야 알아서 인식합니다.

mappers폴더에 LoginMapper.xml이라는 파일을 만들고 아래와 같이 작성합니다.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper    
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"     
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="loginMapper">
	<!-- 등록된 회원 조회 및 로그인시 체크 -->
	<select id="check_user" parameterType="com.test.login.LoginDTO" resultType="java.util.HashMap">
		select id,password from USER_LOGIN_INFO_TB where id="${id}";
	</select>
</mapper>

namespace는 sql연결시 사용할 이름입니다.

일단은 select만 해서 id만을 통해 조회하는 Query문을 작성했습니다.

parameterType과 resultType은 제작한 DTO나 자료형이 사용가능합니다.

항상 모든 경로를 다 적어주는건 힘든일이죠.

 

root-context.xml에 sqlSessionFactory에 한줄을 추가합니다.

<property name="configLocation" value="classpath:/mybatisAlias.xml" />

 

이제 해당 위치에 해당 파일을 만들어줍니다.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0/EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">

<configuration>
	<typeAliases>
		<typeAlias type="com.test.login.LoginDTO" alias="loginDTO"/>
	</typeAliases>
</configuration>

위의 내용을 그대로 넣으시면 됩니다.

typeAlias에서 type은 사용할 자료형입니다.

제작한 DTO를 넣고 loginDTO로 사용가능하게 선언합니다.

 

<!-- 등록된 회원 조회 및 로그인시 체크 -->
<select id="check_user" parameterType="loginDTO" resultType="java.util.HashMap">
	select id,password from USER_LOGIN_INFO_TB where id="${id}";
</select>

작성한 Mapper와 비교를 하면 어떻게 사용하시는지 이해가 되실겁니다.

 

이제 DAO에 sql을 사용할수 있게 선언하고 만든 쿼리문이 동작하나 만들어보겠습니다.

@Autowired
protected SqlSessionTemplate sqlSession;

위의 코드를 추가해줍니다. root-context에서 선언한 내용에 의존성 주입을 해줍니다.

 

@Override
public LoginDTO user_check(String id, String password) {
    LoginDTO login_data = new LoginDTO();
    login_data.setId(id);
    login_data.setPassword(password);

    // selectOne은 결과가 없으면 null을 반환
    HashMap<String, Object> check_user = sqlSession.selectOne("loginMapper.check_user",login_data);
    logger.info("check_user : " + check_user != null ? check_user.toString() : "null");

    if(check_user == null || check_user.get("id").equals(id) == false) {
        // 아이디가 없을때
        login_data = new LoginDTO();
    } else if(check_user.get("password").equals(password) == false) {
        // 입력한 비밀번호가 다를때
        login_data.setPassword("");
    }

    return login_data;
}

위와 같이 코드를 작성합니다. 오버라이드를 했으니 DAO인터페이스에도 선언을 해줘야겠죠.

selectOne은 데이터 1개만 조회할때 쓰입니다.

아까 사용한 네임스페이스와 select문의 id로 해당 쿼리문을 매칭합니다.

전송할 데이터가 있을때만 뒤에 데이터를 실어보내면 됩니다.

 

LoginServiceImpl에 아래 내용을 추가해줍니다.

@Override
public HashMap<String, Object> user_check(String id, String password) {
    // TODO Auto-generated method stub
    HashMap<String, Object> returnVal = new HashMap<String, Object>();

    if (id.isEmpty() && password.isEmpty()) {
        returnVal.put("msg_code", "00001");
        returnVal.put("msg", "입력값 없음");
    } else {
        LoginDTO loginDTO = loginDAO.user_check(id, password);
        if (loginDTO.getId() == null || loginDTO.getId().isEmpty()) {
            returnVal.put("msg_code", "00002");
            returnVal.put("msg", "아이디 없음");
        }else if(loginDTO.getPassword().isEmpty()) {
            returnVal.put("msg_code", "00003");
            returnVal.put("msg", "비밀번호 다름");
        }else {
            returnVal.put("msg_code", "00000");
            returnVal.put("msg", "정상");
        }
    }

    return returnVal;
}

Front-End단에서 msg_code를 통해 분기를 주려고 합니다.

 

이제 controller에 아래 내용을 붙여넣습니다.

@ResponseBody
@RequestMapping(value="/user_check", method = RequestMethod.POST)
public HashMap<String,Object> user_check(@RequestParam String id, @RequestParam String password) {
    HashMap<String,Object> check_data = loginService.user_check(id, password);
    return check_data;
}

그냥 Service에서 온 값을 그대로 보내줍니다. 

 

@RequestMapping(value="/user_check", method = RequestMethod.POST)
public @ResponseBody HashMap<String,Object> user_check(@RequestParam String id, @RequestParam String password) {
    HashMap<String,Object> check_data = loginService.user_check(id, password);
    return check_data;
}

위와 같이 ResponseBody를 안에 써도 상관 없습니다. Rest Api 제작시 JSON형식을 받기 위해 해당 Annotation을 사용합니다.

 

이제 Front-End에서 Ajax통신을 통해 값을 받아보겠습니다.

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>로그인 메인</title>
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
</head>
<body>
<c:choose>
	<c:when test="${msg == 'succ' && typeVal == 'login'}">
		로그인 성공함
		<c:if test="${ !empty login_info }">
			<form action="${pageContext.request.contextPath}/login/user_logout" method="post">
				<input id="id" name="id" type="hidden" value='<c:out value="${login_info.id}" />'>
				<input id="password" name="password" type="hidden" value='<c:out value="${login_info.password}" />'>
				<input id="session_id" name="session_id" type="hidden" value='<c:out value="${login_info.session_id}" />'>
				<input type="submit" value="로그아웃">
			</form>
		</c:if>
	</c:when>
	<c:when test="${msg == 'succ' && typeVal == 'logout'}">
		로그아웃 성공함
	</c:when>
	<c:when test="${msg == 'fail'}">
		로그인이든 로그아웃이든 뭔가 실패함
	</c:when>
	<c:otherwise>
		<!-- 조건식 그외 -->
		안녕 여긴 로그인 페이지
		
		<script>
			function rest_check_user() {
 				var send_data = new Object();
                send_data.id = document.getElementById("id").value;
				
				$.ajax({
				    url:'${pageContext.request.contextPath}/login/user_check', // 요청 할 주소
				    async:true,		// false 일 경우 동기 요청으로 변경
				    type:'POST',	// GET, POST, PUT, PATCH, DELETE 등
				    data: send_data,// 전송할 데이터
				    dataType:'json',// xml, json, script, html
				    //contentType:"application/json",  // 기본값 : application/x-www-form-urlencoded; charset=UTF-8
				    beforeSend:function(jqXHR, settings) {
					    // 전송전 
					    console.log("beforeSend",jqXHR, settings)
				    },success:function(data, textStatus, jqXHR) {
					    // 통신 성공
				    	console.log("success",data, textStatus, jqXHR) 
				    },error:function(jqXHR, textStatus, errorThrown) {
					    // 에러
				    	console.log("error",jqXHR, textStatus, errorThrown)
				    },complete:function(jqXHR, textStatus) {
					    // 성공 or 실패 상관 없이 실행
				    	console.log("complete",jqXHR, textStatus)
				    }
				});
			}
		</script>
		<input type="button" value="중복확인" onclick="rest_check_user()">
	</c:otherwise>
</c:choose>
<form action="${pageContext.request.contextPath}/login/user_login" method="post">
<input id="id" name="id">
<br>
<input id="password" name="password" type="password">
<br>
<input type="submit" value="확인">
</form>
</body>
</html>

Ajax를 사용하기 위해 jquery를 추가합니다.

rest_check_user함수를 보면 ajax사용방법 설명이 있습니다.

 

기본적인 ajax는 form으로 동작하게 되어있더군요.

그래서 기존 웹페이지 에서 받던 @RequestParam으로 받아 값을 확인할 수 있습니다.

 

그럼 form이 아닌 json으로 통신을 해보겠습니다.

@ResponseBody
@RequestMapping(value="/user_check_json", method = RequestMethod.POST)
public HashMap<String,Object> user_check_json(@RequestBody Map<String, Object> map) {
    String id = map.get("id") != null ? map.get("id").toString():"";
    String password = map.get("password") != null ? map.get("password").toString():"";
    HashMap<String,Object> check_data = loginService.user_check(id, password);
    return check_data;
}

위와 같이 @RequestBody를 사용하여 전송되는 Data를 통으로 받습니다. DTO가 있다면 DTO로도 받을 수 있다고 합니다.

 

$.ajax({
    url:'${pageContext.request.contextPath}/login/user_check_json', // 요청 할 주소
    async:true,		// false 일 경우 동기 요청으로 변경
    type:'POST',	// GET, POST, PUT, PATCH, DELETE 등
    data: JSON.stringify(send_data),	// 전송할 데이터
    dataType:'json',// xml, json, script, html
    contentType:"application/json",  // 기본값 : application/x-www-form-urlencoded; charset=UTF-8
    beforeSend:function(jqXHR, settings) {
        // 전송전 
        console.log("beforeSend",jqXHR, settings)
    },success:function(data, textStatus, jqXHR) {
        // 통신 성공
        console.log("success",data, textStatus, jqXHR)
        if(data.msg_code == "00003" || data.msg_code == "00000") {
            alert("아이디 중복 ")
        } else if(data.msg_code == "00001") {
            alert("아이디를 입력하세요")
        } else {
            console.log("가입가능")
        }
    },error:function(jqXHR, textStatus, errorThrown) {
        // 에러
        console.log("error",jqXHR, textStatus, errorThrown)
    },complete:function(jqXHR, textStatus) {
        // 성공 or 실패 상관 없이 실행
        console.log("complete",jqXHR, textStatus)
    }
});

위에 Ajax관련 부분 코드를 변경해주어야합니다.

주석되어있던 contextType에 주석을 제거합니다.

또한 url을 방금 controller 추가한 주소로 변경을합니다.

application/json으로 전송시 값을 받기 위해선 data를 JSON.stringify를 사용하여 JSON형식의 문자열로 변경을 해주어야 데이터를 받을 수 있습니다.제가 다룰지 안다룰지 몰라서 일단 간단하게만 작성하겠습니다.


드디어 기나긴 디비연동 및 Rest API제작 과정이 끝났네요..

사실 값을 전송할 때 @PathVariable이라던지 다른방식으로 처리든 사용이 가능합니다. 저와 함께했던 부분에서 더욱더 붙이며 연습을 해보시면 될것 같습니다.

또한 controller에서 사용하는 페이지를 넘기는 방법도 다양합니다.

또한 많이 사용하는 라이브러리들도 있구요 (예 : tiles, spring security 등)

'JAVA > Spring' 카테고리의 다른 글

3. Spring Framework 개발 따라하기-1  (0) 2020.01.30
2. Spring Framework 프로젝트 설정 및 간단한 실행  (0) 2020.01.28
1. Spring Framework 환경구축하기  (0) 2020.01.27
시작전..  (0) 2020.01.27

WRITTEN BY
아가루이

,

구조 설명이라고 하는게 맞는진 모르겠지만 하나하나씩 추가하며 어떤 파일들을 추가하며

 

제가 할 당시에 많이 쓰이던 라이브러리 들을 연동하겠습니다.

 

하나하나씩 추가하며 따라오시면 될것같습니다.

 

일단 위의 화면을 간단하게 설정 드리겠습니다.

 

다른 부분은 보통 기본적으로 구현하는 부분이며 스프링 기본적인 사용법 튜토리얼이라 생각하심 됩니다.

 

디비연동은 다음에 하겠습니다.

 

/src/main/webapp의 패키지 경로를 웹에서 띄울시 /(root)로 설정된 기본 설정입니다.

이부분의 설정을 조금씩 바뀔수도 있으니까 기억해두심 좋습니다.

 

일단 위와 같이 views 폴더에 login이란 폴더와 login폴더 안에 main이란 jsp파일을 만들겠습니다.

 

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>로그인 메인</title>
</head>
<body>
안녕 여긴 로그인 페이지
</body>
</html>

일단 위와 같이 만들어줬습니다.

 

 

http://localhost:8080/demo/login/main.jsp로 접속하여 파일을 확인하면 열리지 않는걸 확인 가능합니다.

 

이제 우리가 원하는 페이지를 띄우기 위해 Controller를 만들어 보겠습니다.

 

위와 같이 com.test.login이라는 package를 만들고 LoginController라는 java 파일을 만들었습니다.

 

@Controller
@RequestMapping(value="/login")
public class LoginController {

	@RequestMapping(value = "/main")
	public String login_main(Model model) {
		return "login/main";
	}
}

 위와 같이 코드를 작성하였습니다.

하나하나 차츰 설명하는걸로 하겠습니다. 

 

작성 후 http://localhost:8080/demo/login/main으로 접속을 해보겠습니다 잘 뜨는지

 

WARN : org.springframework.web.servlet.PageNotFound - No mapping found for HTTP request with URI [/demo/login/main] in DispatcherServlet with name 'appServlet' 와 같은 워닝이 문구를 확인할수 있습니다.

 

만든 컨트롤러가 정상동작을 하지 않는거 같습니다. 동작하게 만들어 봅시다.

 

servlet-context.xml을 열어봅니다.

 

24번째 줄을 수정하시면 됩니다. com.test.demo 패키지만 바라보게 되어있습니다.

 

이 부분을 수정하시면 됩니다.

<context:component-scan base-package="com.test" />
<context:component-scan base-package="com.test.*" />
<context:component-scan base-package="com.test.**" />

3가지중 하나로 바꾸시면 됩니다. 동작은 동일하게 가능합니다.

저장후 서버를 재시작 후 다시 해당 페이지에 접속을 하면 페이지가 잘 보입니다.

 

DB연동은 나중에 하고 MVC패턴에 대해 구현하려 합니다.

일단 만든 로그인엔 간단하게 로그인과 로그아웃이 있죠.

그럼 하나씩 차근차근 추가하며 어떻게 사용하는지(?) 차츰 설명하겠습니다.

 

DTO(Data Transfer Object) 파일을 생성해보겠습니다.

public class LoginDTO {
	private String id;
	private String password;
	private String session_id;

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public String getSession_id() {
		return session_id;
	}

	public void setSession_id(String session_id) {
		this.session_id = session_id;
	}
}

com.test.login에 LoginDTO라는 java파일을 위와 같이 만들었습니다.

쉽게 데이터를 연동할때 사용할 데이터 객체를 선언하는 부분이라고 생각하시면 됩니다.

DTO = VO이긴 하지만 VO는 read only속성이 있다고 합니다.

 

DAO(Data Access Object) 파일을 생성해보겠습니다.

public interface LoginDAO {
	public LoginDTO user_login(String id,String password);
	public LoginDTO user_logout(String id, String password, String session_id);
}

LoginDAO라는 파일을 위와 같이 interface로 선언합니다. 일단 간단한 로그인과 로그아웃정도만 선언하겠습니다.

 

interface를 상속받아 구현하겠습니다.

@Repository("LoginDAO")
public class LoginDAOImpl implements LoginDAO {
	@Override
	public LoginDTO user_login(String id, String password) {
		// TODO Auto-generated method stub
		LoginDTO login_data = new LoginDTO();
		
		if(id.equals("test") && password.equals("1111")) {
			login_data.setId(id);
			login_data.setPassword(password);
			login_data.setSession_id("qwer1234");
		} else {
			login_data.setId(id);
			login_data.setPassword(password);
			login_data.setSession_id("");
		}
		
		return login_data;
	}
	
	@Override
	public LoginDTO user_logout(String id, String password, String session_id) {
		// TODO Auto-generated method stub
		LoginDTO login_data = new LoginDTO();
		
		if(id.equals("test") && password.equals("1111")) {
			login_data.setId("");
			login_data.setPassword("");
			login_data.setSession_id("");
		} else {
			login_data.setId(id);
			login_data.setPassword(password);
			login_data.setSession_id(session_id);
		}
		
		return login_data;
	}
}

 

로그인시 id, password가 맞다면 세션값을 내려주고 아니면 세션값을 빈값으로 내려줍니다.

로그아웃은 id, password, session_id가 맞으면 빈값으로 내려주고 아니면 받은 값을 반환합니다.

 

해당 DAO에는 사실 디비 연결부분을 처리해주시면 됩니다. 이번 포스팅에는 디비연동이 없으니 그냥 고정값으로만 처리했습니다.

 

이제 service를 선언하겠습니다.

public interface LoginService {
	public LoginDTO user_login(String id, String password);
	public LoginDTO user_logout(String id, String password, String session_id);
}
@Service("LoginService")
public class LoginServiceImpl implements LoginService {
	// log 찍는용
	private static final Logger logger = LoggerFactory.getLogger(LoginServiceImpl.class);
	
	@Autowired
	LoginDAOImpl loginDAO;
	
	@Override
	public LoginDTO user_login(String id, String password) {
		// TODO Auto-generated method stub
		LoginDTO user_data = loginDAO.user_login(id, password);
		
		if(user_data.getSession_id().equals("")){
			logger.info("로그인 실패");
		}else {
			logger.info("로그인 성공");
		}
		
		return user_data;
	}
	@Override
	public LoginDTO user_logout(String id, String password, String session_id) {
		// TODO Auto-generated method stub
		LoginDTO user_data = loginDAO.user_logout(id, password, session_id);
		
		if(user_data.getSession_id().equals("") && user_data.getId().equals("") && user_data.getPassword().equals("")){
			logger.info("로그아웃 성공");
		}else {
			logger.info("로그아웃 실패");
		}
		
		return user_data;
	}
}

interface로 선언 후 실제 구현을 합니다.

아까 만든 DAO를 의존성주입하여 사용합니다.

 

일단 log가 찍히게 만들었습니다. 여기서 해당 부분 서비스 로직을 구현하시면 됩니다.

 

@Controller
@RequestMapping(value="/login")
public class LoginController {
	private static final Logger logger = LoggerFactory.getLogger(LoginController.class);
	
	@Autowired
	LoginServiceImpl loginService;

	@RequestMapping(value =  {"/main","/"})
	public String login_main(Model model, @RequestParam(value="typeVal", required = false) String typeVal, @RequestParam(value="msg", required = false) String msg) {
		logger.info("login main page open");
		
		if(msg != null && typeVal != null) {
			logger.info(String.format("msg : %s, type : %s", msg,typeVal));
			model.addAttribute("msg", msg);
			model.addAttribute("typeVal", typeVal);
		}
		return "/login/main";
	}
	
	@RequestMapping(value = "/user_login",method = {RequestMethod.POST,RequestMethod.GET})
	public String user_login(@RequestParam(value = "id",required = true, defaultValue = "") String id, @RequestParam(value = "password",required = true, defaultValue = "") String password) {
		LoginDTO user_data = loginService.user_login(id, password);
		logger.info(user_data.toString());
		
		String msg = "";
		if(user_data.getSession_id().isEmpty() == false) {
			msg = "succ";
		}else {
			msg = "fail";
		}
		
		return String.format("redirect:/login/main?typeVal=login&msg=%s", msg);
	}
	
	@RequestMapping(value = "/user_logout", method = RequestMethod.POST)
	public String user_logout(@RequestParam String id, @RequestParam String password, @RequestParam String session_id) {
		LoginDTO user_data = loginService.user_logout(id, password, session_id);
		logger.info(user_data.toString());

		String msg = "";
		if (user_data.getSession_id().isEmpty() && user_data.getId().isEmpty() && user_data.getPassword().isEmpty()) {
			msg = "succ";
		} else {
			msg = "fail";
		}

		return String.format("redirect:/login/main?typeVal=logout&msg=%s", msg);
	}
}

이제 위와 같이 controller를 변경합니다.

 

이제 로그인을 테스트 해보기 위해 /views/login/main.jsp를 수정합니다.

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>로그인 메인</title>
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
</head>
<body>
안녕 여긴 로그인 페이지
<form action="${pageContext.request.contextPath}/login/user_login" method="post">
<input id="id" name="id">
<br>
<input id="password" name="password" type="password">
<br>
<input type="submit" value="확인">
</form>
</body>
</html>

 

서버를 재시작 하고 테스트를 해보시면 됩니다.

 

같은 페이지라 구분은 안가지만 서버 로그엔 잘 찍힙니다.

 

요즘엔 Front-End와 Back-End를 분리하여 개발을 많이 한다고 하던데 그래도 혹시나 웹과 연동하여 직접 데이터를 주고 받는다면 보통 JSTL을 많이 쓰게 될것입니다.

 

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>로그인 메인</title>
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
</head>
<body>
<c:choose>
	<c:when test="${msg == 'succ' && typeVal == 'login'}">
		로그인 성공함
	</c:when>
	<c:when test="${msg == 'fail'}">
		로그인이든 로그아웃이든 뭔가 실패함
	</c:when>
	<c:otherwise>
		<!-- 조건식 그외 -->
		안녕 여긴 로그인 페이지
	</c:otherwise>
</c:choose>
<form action="${pageContext.request.contextPath}/login/user_login" method="post">
<input id="id" name="id">
<br>
<input id="password" name="password" type="password">
<br>
<input type="submit" value="확인">
</form>
</body>
</html>

JSTL 선언을 하고 c: 이렇게 된 부분을 확인하시면 됩니다.

위에 사용한 부분은 if else if else 구조입니다.

 

초기화면 성공 실패 시 화면이 다른부분을 확인해보시면 됩니다.

 


이제 로그아웃을 붙이겠습니다.

로그아웃시 필요한 값은 id, password, session_id입니다.

페이지 이동이엿다면 model에서 addAttribute로 가능했겠지만 저는 redirect를 시키기 때문에 redirect를 시키는 방법을 추가하겠습니다.

 

구글링을 해보니 redirect시에 값을 넘기는 방법이 있더군요 그 방법으로 구현하겠습니다.

	@RequestMapping(value = "/user_login", method = { RequestMethod.POST, RequestMethod.GET })
	public String user_login(RedirectAttributes redirectAttributes,
			@RequestParam(value = "id", required = true, defaultValue = "") String id,
			@RequestParam(value = "password", required = true, defaultValue = "") String password) {
		LoginDTO user_data = loginService.user_login(id, password);
		logger.info(user_data.toString());

		String msg = "";
		if (user_data.getSession_id().isEmpty() == false) {
			msg = "succ";
			redirectAttributes.addFlashAttribute("login_info", user_data);
		} else {
			msg = "fail";
		}

		return String.format("redirect:/login/main?typeVal=login&msg=%s", msg);
	}

위와 같이 RedirectAttributes가 추가되었습니다. 또한 값을 login_info라는 이름으로 로그인 정보를 넘겨줍니다.

원래는 addaddAttribute로 값을 전달주려 했으니 String만 지원하더라구요 Object를 전달하기 위해 addFlashAttribute를 사용하여 값을 넘겨줍니다.

(또한, addaddAttribute는 GET방식의 데이터 전송이라 하네요)

 

이제 값을 받기 위해서 redirect시키는 페이지도 변경해야겠죠?

찾아봤는데 백단에서 받는게 굉장히 귀찮더군요.. 그래도 잘 왔는지 로그는 찍어봐야 하니 Back-End에서 받아서 로그를 찍어보겠습니다.

	@RequestMapping(value = { "/main", "/" }, method = { RequestMethod.POST, RequestMethod.GET })
	public String login_main(Model model, @RequestParam(value = "typeVal", required = false) String typeVal,
			@RequestParam(value = "msg", required = false) String msg, HttpServletRequest req) {
		logger.info("login main page open");

		if (msg != null && typeVal != null) {
			logger.info(String.format("msg : %s, type : %s", msg, typeVal));
			model.addAttribute("msg", msg);
			model.addAttribute("typeVal", typeVal);
		}

		Map<String, ?> flashMap = RequestContextUtils.getInputFlashMap(req);
		if (flashMap != null) {
			LoginDTO login_info = (LoginDTO) flashMap.get("login_info");
			logger.info("login_info : " + login_info.toString());
		}

		return "/login/main";
	}

쫌 받는 방법이 귀찮지만 HttpHttpServletRequest을 사용해야하고 FlashMap을 받아와야 값을 받는게 가능하네요.

자료형이 다르다거나 하면 예외 처리가 귀찮을꺼 같네요...

 

login/main페이지에서 login_info라는 로그가 잘 찍히는걸 확인했습니다. 이제 웹페이지에 보여주겠습니다.

이미 redirectAttributes를 사용하여 attribute에 추가가 되어 있으므로 따로 처리해줄 필요는 없습니다.

 

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>로그인 메인</title>
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
</head>
<body>
<c:choose>
	<c:when test="${msg == 'succ' && typeVal == 'login'}">
		로그인 성공함
		<c:out value="${login_info}" />
	</c:when>
	<c:when test="${msg == 'fail'}">
		로그인이든 로그아웃이든 뭔가 실패함
	</c:when>
	<c:otherwise>
		<!-- 조건식 그외 -->
		안녕 여긴 로그인 페이지
	</c:otherwise>
</c:choose>
<form action="${pageContext.request.contextPath}/login/user_login" method="post">
<input id="id" name="id">
<br>
<input id="password" name="password" type="password">
<br>
<input type="submit" value="확인">
</form>
</body>
</html>

c:out을 사용하여 정상적으로 값이 넘어왔는지 확인해보겠습니다.

 

위와 같이 보인다면 값은 정상적으로 넘어온걸 확인할 수 있습니다.

이제 해당 정보들을 사용하여 로그아웃으로 값을 넘겨보겠습니다.

 

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>로그인 메인</title>
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
</head>
<body>
<c:choose>
	<c:when test="${msg == 'succ' && typeVal == 'login'}">
		로그인 성공함
		<c:if test="${ !empty login_info }">
			<form action="${pageContext.request.contextPath}/login/user_logout" method="post">
				<input id="id" name="id" type="hidden" value='<c:out value="${login_info.id}" />'>
				<input id="password" name="password" type="hidden" value='<c:out value="${login_info.password}" />'>
				<input id="session_id" name="session_id" type="hidden" value='<c:out value="${login_info.session_id}" />'>
				<input type="submit" value="로그아웃">
			</form>
		</c:if>
	</c:when>
	<c:when test="${msg == 'succ' && typeVal == 'logout'}">
		로그아웃 성공함
	</c:when>
	<c:when test="${msg == 'fail'}">
		로그인이든 로그아웃이든 뭔가 실패함
	</c:when>
	<c:otherwise>
		<!-- 조건식 그외 -->
		안녕 여긴 로그인 페이지
	</c:otherwise>
</c:choose>
<form action="${pageContext.request.contextPath}/login/user_login" method="post">
<input id="id" name="id">
<br>
<input id="password" name="password" type="password">
<br>
<input type="submit" value="확인">
</form>
</body>
</html>

로그인을 성공하고 login_info가 재대로 넘어왔다면 값을 저장하고 로그아웃 버튼이 나오게 되어있습니다.

 

로그아웃관련 처리는 전에 처리해둔 코드가 정상동작 하나 확인해보시면 됩니다.

	@RequestMapping(value = "/user_logout", method = RequestMethod.POST)
	public String user_logout(@RequestParam String id, @RequestParam String password, @RequestParam String session_id) {
		LoginDTO user_data = loginService.user_logout(id, password, session_id);
		logger.info(user_data.toString());

		String msg = "";
		if (user_data.getSession_id().isEmpty() && user_data.getId().isEmpty() && user_data.getPassword().isEmpty()) {
			msg = "succ";
		} else {
			msg = "fail";
		}

		return String.format("redirect:/login/main?typeVal=logout&msg=%s", msg);
	}

 

로그인 성공 후 로그아웃 버튼을 누를시 id, password, session_id가 빈값으로 내려오는걸 확인할 수 있습니다.

 

이번 포스팅은 여기까지 하겠습니다.

 

다음엔 디비연동과 RESTful api관련 작업을 진행할거 같습니다.

Tiles는 고민중입니다.

'JAVA > Spring' 카테고리의 다른 글

4. Spring Framework 개발 따라하기-2  (0) 2020.02.07
2. Spring Framework 프로젝트 설정 및 간단한 실행  (0) 2020.01.28
1. Spring Framework 환경구축하기  (0) 2020.01.27
시작전..  (0) 2020.01.27

WRITTEN BY
아가루이

,