본문 바로가기
Back-End/Spring Boot

Spring Boot - 로그인 예제 ( html, server 연동 )

by 코젼 2022. 7. 26.
728x90
반응형

2022-07-26(27일차)


💁‍♀️ 로그인 html과 서버를 연동해봅시다.

해당 글과 이어집니다!

2022.07.25 - [Back-End/Spring Boot] - Spring - MyBatis VO 작업

 

Spring - MyBatis VO 작업

💡MyBatis 관련 라이브러리 추가 💁‍♀️MyBatis 추가 🔸Maven 프로젝트 MyBatis 추가 ▪️ pom.xml에 디펜던시 추가 org.mybatis.spring.boot mybatis-spring-boot-starter 2.2.2 ​ ▪️ pom.xml 선택 후 마..

cojyeon.tistory.com


◾ thymeleaf가 루트 디렉터리가 src/main/resources/templates라고 생각하기 때문에 html을 그 위치에 넣는다.

◾ html페이지는 templates 디렉터리 하위에 넣는다.
◾ js, img, css 들은 다른 디렉터리에 들어간다.

🔸순서
◾ html페이지를 만들고 서버에서 주소를 호출한다.
◾ 주소를 받는 Controller 패키지를 생성한다.
◾ Service, dao, vo 패키지도 만든다.
◾ 쿼리를 넣는다.

🔸경로
◾ 맨 앞이 /로 시작하지 않으면 상대경로이다.
◾ /로 시작할 경우는 절대경로이다.
 -- 예를 들어, href = "/css/login.css" 라면 절대경로이다.
◾ default 경로 앞은 localhost의 루트 안에 css/login.css이다.

◾ 웹서버 루트 디렉터리(웹루트)는 사용자들도 접근할 수 있으나, 손쉽게 접근하여 img, js 파일을 해킹한다.
◾ 스프링부트는 정적 타입들을 resources안에 static을 만들고 그 안에 두면 static폴더를 웹루트로 인식한다.
 -- html은 templates에 넣으면 루트라고 생각하는 것과 유사하다.
 -- 루트의 js하면 resources 밑에 static밑에 js폴더를 찾는다.

🔸<form>
action은 호출할 주소로 들어간다.
method가 post면 post방식으로 받는다.
submit이 눌려지게 되면 서버로 전송을 하는데, 전송을 하면 반드시 이 페이지는 사라진다.
 -- 요청을 하고 사라지는 페이지이다. (페이지가 바뀐다.)
 -- 따라서, 결과가 오든 안 오든 타입이 submit으로 두면 페이지가 지워지기 때문에 대부분의  jquery에서는 submit에서는 버튼을 주지 않고 일반 버튼을 준다.
 -- 지우지 않고 사용하는 방법은 jquery로, e.preventDefault(); 를 사용하면 된다.
    -- 기본을 방지시켰다라는 의미인데, 기본은 submit을 누르면 페이지를 지우고 다른 페이지로 이동하는 작업을 막은 것이다.
    -- 이벤트 전파도 막아줄 수 있다.
Ajax방식으로 비동기 방식을 하면, 서버로 json같은 결과만 더 보여주거나 다른 페이지로 이동하거나 할 수 있다.
동작으로 제어하고, 페이지를 없애고 바꾸고 하는 케이스는 존재하지 않는다.


🔸<input>
◾ jquery는 id가 필수
◾ 화면에 넘겨줄 때(서버에게 넘겨줄 때)는 반드시 name을 적어야한다.
 -- 서버로 name이 갈 것이다.
 ex) name="user_id", name="user_pw"이면 user_iduser_pw가 서버로 간다.
◾ name은 중복이 가능하지만, id는 중복을 허용하지 않는다.

🔸Controller에서 값을 받는 것
◾ 명칭을 직접 주어 받는다.
◾ 커맨드 객체로 미리 받을 것을 정의해 놓는다.
 -- user_id, user_pw는 미리 정의해 두어야 한다.

💡 유용한 확장 프로그램

코드를 깔끔하게 정리해준다.
간이용 서버

뷰, 리액트 사용하려면 ES6 - js


💡실습

📝sample01.html

◾ sample01.html을 작성한다.
◾ action은 폼 데이터(form data)를 서버로 보낼 때 해당 데이터가 도착할 URL을 명시한다.
◾ 임의로 value값을 hunter, 12345로 준다.
◾ 입력 값을 표시는 하되 값을 수정하지 못하게 할 수 있다. -- disable

value로 값이 표시되어 있다.
js도 절대경로로 설정한다.
thymeleaf를 사용한다고 명시한다.
html 페이지 실행 화면이다.

 


◾ sts를 실행해 controller, dao, service, vo 역할을 하는 패키지를 나눈다.

업무별 패키지 생성

◾ 클래스 안에 들어가는 건 멤버변수, 멤버함수
◾ 함수 안에 있는 건 지역변수, 밖에 있는 건 전역변수

📝SampleController.java

package com.shop.sample.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;

@Controller // 페이지 주소를 돌려준다.
public class SampleController {
//	스프링한테 @GetMapping을 통해 사용자의 주소를 Get방식으로 받으라고 한다.
	@GetMapping("/sample/exam01")
	public String exam01() { // 페이지 주소가 String으로 올 것이다.
		return "sample/sample01"; // sample/sample01.html을 return한다.
	}
	
	@GetMapping("/sample/exam02")
	public String exam02() { 
		return "sample/sample02";
	}
}
◾ post방식이어서 whitelabel Error Page가 뜬다.
◾ get방식인지 post방식인지 구분해야한다.
◾ 없으면 없는대로, 있으면 있는대로 보여줄 때는 @RequestMapping으로 처리하면 된다.

@GetMapping할 때는 제대로 뜨는 것을 확인할 수가 있다.


💡Thymeleaf 사용 및 소스코드 수정

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge; chrome=1">
    <!-- 장비 기준, 100%-->
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <!-- <script src="/js/jquery.js"></script> -->
</head>

<body>

    <div class="login_wrap">
        <h1>로그인</h1>
        <form class="login_f" method='get' action='/sample/exam02'>
            <p>
                <label for="user_id">ID</label>
                <input type="text" name="user_id" id="user_id" value="hunter" />
            </p>
            <p>
                <label for="user_pw">PW</label>
                <input type="password" name="user_pw" id="user_pw" value="12345" />
            </p>
            <p><input type="submit" value="로그인" class="login_btn" /></p>
        </form>
    </div>

    <div>
        User_ID : <span th:text="${user_id}"></span>
    </div>
</body>

</html>

📝SampleController.java -- STS

package com.shop.sample.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller // 페이지 주소를 돌려준다.
@RequestMapping("/sample") // 클래스 전체에 공통으로 /sample이 적용된다.
public class SampleController {
//	스프링한테 @GetMapping을 통해 사용자의 주소를 Get방식으로 받으라고 한다.
	@GetMapping("/exam01") // Get방식
	public String exam01() { // 페이지 주소가 String으로 올 것이다.
		return "sample/sample01"; // sample/sample01.html을 return한다.
	}

	@PostMapping("/exam01")
	public String exam01_p(Model model) {
		return "sample/sample01";
	}

	@RequestMapping("/exam02") // /exam02라고 요청이 올 경우
	// 모델을 주지 않으면 스프링이 준 모델을 사용하지 못한다. -- 페이지에서도 알고 있다.
	public String exam02(Model model) { // html에 적기만 해놓은 타임리프를 해석할 수 없기 때문에 서버에서 Model에 담는다.
		// key값을 userId라고 주어도 상관없다. 그러나 html에서도 th:text="${userId}"로 바꾸어야 한다.
		model.addAttribute("user_id", "Test"); // key값, value값
		return "sample/sample01";
	}
}

◾ 버튼을 누르면 /exam02로 들어온다.

로그인 버튼을 누를 경우


💡 SampleService 자바 파일 생성


저번에 만들었던 SampleVO 이용

◾ SampleVO를 사용하기 위해서 SampleVO를 생성해야한다.

new를 설정하지 않으면 클래스를 사용할 수 없다.

◾ myBusiness를 호출하면 SampleVO가 넘어온다.
◾ 결과는 주었지만 한 번만 호출할 수 있다. (결과를 보관하지 않음) -- 계속해서 db에 붙어야 한다.
 -- db에 붙는 작업이 빠르게 이루어지지 않기 때문에 오래 걸린다.
 -- 같은 시간에 다른 사람이 같은 데이터를 수정할 경우 원하는 결과값이 나오지 않을 수 있다.
◾ 결과를 받아온 것을 다시 사용하기 위해 변수에 보관해둔다.

◾ resultObj 변수에 결과값을 저장한다.

Controller에서는 Service를 호출해서 service에 있는 mtyBuisness를 호출해서 resultObj변수에 저장한다.

resultObj의 getName 함수를 호출한다.


⭐스프링의 장점!! new를 할 필요가 없다.

◾ @Autowired를 전역에 선언하여 메서드에서 new 없이 사용할 수 있도록 한다.


💡 HttpServletRequest 사용

◾ HttpServletRequest : 사용자가 보낸 정보 ( ip, 사용자가 요청한 변수, 브라우저... ) 
◾ 인터넷 연결하면서 만들어진 정보들이 모두 들어가있다.
◾ 클래스이다.
◾ 모든 정보를 request 변수에 저장한다.
◾ service에 정보를 모두 다 넘긴다.

📝SampleController.java 일부

📝SampleService.java


💡 DAO 작업

◾ 이미 만들어둔 ISampleDAO 파일을 사용한다.
사진 오류 ISampleDAO가 아니라, ISampleMyDAO를 사용한다.

13, 14번째 줄과 19번째 줄은 동일하다.


◾ SampleVO 붙이는 법


💡자바 bulid 다시 하는 법

◾ 서버 강제 refresh
◾ 크롬은 캐시를 지워줘야 할 때도 있다.


💡 사용자가 입력한 데이터를 getParameter를 통해 읽어온다.

◾ 값을 가져와서 각 userId, userPW 변수에 저장한다.


💡 DAO와 쿼리를 생성한다.

인터페이스 ISampleMyDAO를 생성한다.
mybatis 폴더 안에 sample폴더를 생성한다.
위에서 생성한 sample폴더 안에 ISampleMyDAO.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의 경로는 만들어두었던 com.shop.sample.dao.ISampleMyDAO 위치로 정한다.

◾ ISampleMyDAO.java에 있는 selectEmail은 ISampleMyDAO.xml에 있는 id의 값과 동일하다.
◾ 쿼리문의 조건을 걸 때 email은 db에 있는 email 컬럼을 가르킨다.
◾ parameterType은 HashMap으로 하기로 했으므로, java.util.HashMap의 값을 넣는다.


◾ MySQL 문자열 합치기

SELECT * FROM member
WHERE eamil LIKE CONCAT('%', 'test', '%')

◾ 쿼리문도 동일하게 들어간다.

select * from member email like concat('%', #{userID}, '%')

◾ concat을 이용하여 합친 문자열을 mapParam에 넣는다.


◾ key로 사용할 수 있는 건 String만 가능하나, value는 모든 Object가 가능하다.

◾ 22, 23번째 줄 : userID에 정보를 받아온 request안에 있는 파라미터 값 "user_id"를 가져와 저장하고, userPW에 정보를 받아온 request안에 있는 파라미터 값 "user_pw"를 가져와 저장한다.

◾ 27번째 줄 : 부모 클래스 타입 Map<String, String> mapParam 객체는 자식 클래스 타입 HashMap<String, String>을 참조한다. 
◾ 28번째 줄 : mapParam객체 안에 key가 "userId"이고 value가 userId인 값을 넣는다. value는 22번째줄에서 선언한 변수이다.
◾ 30번째 줄 : SampleVo 타입인 vo 변수에 ISampleMyDAO 인터페이스로 선언된 sampleMyDao에 있는 selectEmail 파라미터 안에 mapParam 값을 모두 전달한다.

◾ 13번째 줄 : 인터페이스 ISampleMyDAO안에 selectEmail 함수를 선언한다.
반환타입은 SampleVO이다.
key : String, value : String형인 Map인 map을 파라미터로 가진다.


💡오류 수정


💡실행


💡소스코드

📝sample01.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge; chrome=1">
    <!-- 장비 기준, 100%-->
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <!-- <script src="/js/jquery.js"></script> -->
</head>

<body>

    <div class="login_wrap">
        <h1>로그인</h1>
        <form class="login_f" method='get' action='/sample/exam02'>
            <p>
                <label for="user_id">ID</label>
                <input type="text" name="user_id" id="user_id" value="hunter" />
            </p>
            <p>
                <label for="user_pw">PW</label>
                <input type="password" name="user_pw" id="user_pw" value="12345" />
            </p>
            <p><input type="submit" value="로그인" class="login_btn" /></p>
        </form>
    </div>

    <div>
        User_ID : <span th:text="${userId}"></span>
    </div>
</body>

</html>

📝SampleController.java

package com.shop.sample.controller;

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import com.shop.sample.service.SampleService;
import com.shop.vo.SampleVO;

@Controller // 페이지 주소를 돌려준다.
@RequestMapping("/sample") // 클래스 전체에 공통으로 /sample이 적용된다.
public class SampleController {
	@Autowired
	SampleService service;
	
//	스프링한테 @GetMapping을 통해 사용자의 주소를 Get방식으로 받으라고 한다.
	@GetMapping("/exam01") // Get방식
	public String exam01() { // 페이지 주소가 String으로 올 것이다.
		return "sample/sample01"; // sample/sample01.html을 return한다.
	}

	@PostMapping("/exam01")
	public String exam01_p(Model model) {
		return "sample/sample01";
	}

	@RequestMapping("/exam02") // /exam02라고 요청이 올 경우
	// 모델을 주지 않으면 스프링이 준 모델을 사용하지 못한다. -- 페이지에서도 알고 있다.
	public String exam02(HttpServletRequest request, Model model) { // html에 적기만 해놓은 타임리프를 해석할 수 없기 때문에 서버에서 Model에 담는다.
		
		SampleVO resultObj = service.myBusiness(request);
		
		// key값을 userId라고 주어도 상관없다. 그러나 html에서도 th:text="${userId}"로 바꾸어야 한다.
		model.addAttribute("userId", resultObj.getEmail()); // key값, value값
		return "sample/sample01";
	}
}

📝ISampleMyDAO.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
    PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
    "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    
<mapper namespace="com.shop.sample.dao.ISampleMyDAO">
     <select id="selectEmail" parameterType="java.util.HashMap" resultType="com.shop.vo.SampleVO">
        select * from member where email like concat('%', #{userId}, '%')
    </select>
</mapper>

📝ISampleMyDAO.java

package com.shop.sample.dao;

import java.util.Map;

import org.apache.ibatis.annotations.Mapper;

import com.shop.vo.SampleVO;

@Mapper //MyBatis에서 사용하는 @Mapper를 호출을 하면 스프링이 데이터를 넣어준다.
public interface ISampleMyDAO {
	// parameter를 Map으로 주는 이유는 파라미터가 여러개이고 어떻게 바뀔지 모르기 때문에 Map으로 넘겨준다.(key value로 이루어짐) -- 파라미터가 몇 개인지 상관없다.
	// 인터페이스에서는 함수 이름, 파라미터만 결정해서 만들면 된다.
	public SampleVO selectEmail(Map<String, String> map); //selectEmail은 쿼리파일에 id로 들어가있을 것이다.
}

📝SampleService.java

package com.shop.sample.service;

import java.util.HashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.shop.sample.dao.ISampleMyDAO;
import com.shop.vo.SampleVO;

@Service
public class SampleService {
	@Autowired
	ISampleMyDAO sampleMyDao;
	// db에게 데이터 값을 가져오라고 시킨다.
	// 함수는 호출한 쪽으로 돌려준다.
	public SampleVO myBusiness(HttpServletRequest request) {
		
		String userId = request.getParameter("user_id");
		String userPW = request.getParameter("user_pw");
		
		// 넘겨줄 parameter를 준비한다.
		// 데이터 형태는 Map<String, String>
		// HashMap으로 원하는 값을 넘겨준다.
		Map<String, String> mapParam = new HashMap<String, String>(); // key로 사용할 수 있는 건 String만 가능하나, value는 모든 Object가 가능하다.
		mapParam.put("userId", userId);
		
		// 만든 파라미터를 파라미터로 넘겨주어 selectEmail을 실행한다.
		SampleVO vo = sampleMyDao.selectEmail(mapParam); // 파라미터로 보낼 수 있다.
		
		return vo; // SampleVO 타입인 vo를 반환한다.
	}
}
728x90
반응형

댓글