Spring/게시판 만들기 프로젝트

[Spring Boot] #2_1 게시판 만들기

sujin7837 2020. 12. 9. 16:11
반응형

학습 목표

-데이터베이스에 사용자 데이터 추가

-개인정보 수정 기능 구현

-질문하기, 질문목록 기능 구현

 

학습 목차

2-1. QnA HTML 템플릿, H2 데이터베이스 설치, 설정, 관리 툴 확인

2-2. 자바 객체와 테이블 매핑, 회원가입 기능 구현

2-3. HTML 정리, URL 정리

2-4. 개인정보 수정 기능 구현 1

2-5. 개인정보 수정 기능 구현 2

2-6. 원격 서버에 소스 코드 배포

 

 

[html 템플릿 다운 및 h2 데이터베이스 설치]

1.

github.com/slipp/web-application-server: 코드를 clone해서 sts로 가져옵니다.

(import->maven->existing maven project)

 

2. wepapp 하위 파일들을 통째로 복사해서 static 하위에 붙여넣기를 합니다.

(구현하고자 하는 정적인 템플릿을 bootstrap 등의 사이트에서 다운받아서 사용함)

 

3. MVN repository 사이트에서 H2 Database engine을 검색하여 dependency를 복사합니다.

 

4. pom.xml 파일의 dependency에 복사한 내용을 붙여넣기 합니다.(H2 database 설치 완료)

 

5. 'localhost: 8080/h2-console'로 접속합니다.

 

 

 

[JPA 설치]

5

1. MVN repositoty에서 spring-boot jpa를 검색하여 'spring boot data JPA starter' dependency를 복사합니다.

 

2. pom.xml 파일의 dependency에 복사한 내용을 붙여넣기 합니다.(jpa 설치 완료)

parent 태그에 버전이 추가되어 있으므로 버전은 붙여넣지 않아도 됩니다.

 

//User.java

@Entity	//1.
public class User {
	@Id	//2.
    @GeneratedValue	//3.
    private Long id;
    
    @Column(nullable=false, length=20)	//4.
	private String userId;
    
    private String password;
    private String name;
    private String email;
    
    public void setUserId(String userId) {
    	this.userId=userId;
    }
    
    public void setPassword(String password) {
    	this.password=password;
    }
    
    public void setName(String name) {
    	this.name=name;
    }
    
    public void setEmail(String email) {
    	this.email=email;
    }
    
    @Override
    public String toString() {	
    	return "User [userId=" + userId + ", password=" + password + ", name=" + name, "email=" + email +"]";
    }
}

1. @Entity: 데이터를 database의 entity로 지정합니다.

 

2. @Id: 데이터베이스의 primary key로 지정합니다.

 

3. @GeneratedValue: 하나의 데이터가 추가될 때마다 데이터베이스에서 자동으로 id 값이 1씩 증가되도록 해줍니다.

 

4. userId 값이 null이 되지 않도록 해줍니다. 

(어노테이션을 누르고 f3를 누르면 해당하는 어노테이션의 정보로 이동할 수 있습니다.)

 

5. 어노테이션을 추가해서 데이터베이스와 연결이 가능해진 것은 'jpa'를 사용했기 때문입니다.

 

 

[Spring Boot H2 Database 설정]

spring.datasource.url=jdbc:h2:~/my-slipp	//2.
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=

1. resources -> application.properties 에 위의 코드를 추가해줍니다.

 

2. 접속하고자 하는 jdbc url을 적어줍니다.

 

//database에 데이터를 삽입하거나 조회하기 위해 필요한 interface
//UserRepository.java

public interface UserRepository extends JpaRepository<User, Long>{	//1.
}

1. JpaRepository는 User에 대한 Repository이며 User의 id type은 Long 입니다.

 

//UserController.java

@Controller
public class UserController {
	@Autowired	//1.
	private UserRepository userRepository;

	@PostMapping("/create")
	public String create(User user) {
    	System.out.println("user : " + user);
        userRepository.save(user);	//2.
    	return "redirect:/list";	
    }
    
    @GetMapping("/list")	
    public String list(Model model) {
    	model.addAttribute("users", userRepository.findAll());	//3.
    	return "list";
    }    
}

1. UserRepository가 어딘가에 있다고 생각하고 가져다 쓰기만 하면 됩니다.

 

2. userRepository에 save 메소드가 있기 때문에

users.add(user);

대신에 2. 코드를 사용할 수 있습니다.

 

3. userRepository.findAll()을 이용하면 더 이상 List가 필요하지 않습니다.

 

<!--form.html-->

<form action="/create" method="post" action="/user/create">	
	<div class="form-group">
    	<label for="userId">사용자 아이디</label>
        <input type="text" class="form-control" name="userId" placeholder="사용자 아이디">
    </div>
    <div class="form-group">
    	<label for="password">Password</label>
        <input type="password" class="form-control" name="password" placeholder="비밀번호">
    </div>
    <div class="form-group">
    	<label for="name">이름</label>
        <input type="text" class="form-control" name="name" placeholder="이름">
    </div>
    <div class="form-group">
    	<label for="email">이메일</label>
        <input type="email" class="form-control" name="email" placeholder="이메일">
    </div>
    <button type="submit" class="btn btn-default">Submit</button>
</form>
//변경: PostMapping과 GetMapping의 id(url) 수정
//UserController.java

@Controller
public class UserController {
	@Autowired	
	private UserRepository userRepository;

	@PostMapping("/user/create")
	public String create(User user) {
    	System.out.println("user : " + user);
        userRepository.save(user);	
    	return "redirect:/user/list";	
    }
    
    @GetMapping("/user/list")	
    public String list(Model model) {
    	model.addAttribute("users", userRepository.findAll());	
    	return "list";
    }    
}
<!--templates 하위 파일로 user를 만들고 user 하위 파일로 list.html을 만듭니다.-->
<!--list.html-->

<tbody>
	{{#users}}	
	<tr>
    	<th scope="row">{{id}}</th>
        <td>{{userId}}</td>
        <td>{{name}}</td>
        <td>{{email}}</td>
        <td><a href="#" class="btn btn-success" role="button">수정</a></td>
    </tr>
    {{/users}}
</tbody>
//변경2: return의 url 변경
//UserController.java

@Controller
public class UserController {
	@Autowired	
	private UserRepository userRepository;

	@PostMapping("/user/create")
	public String create(User user) {
    	System.out.println("user : " + user);
        userRepository.save(user);	
    	return "redirect:/user/list";	
    }
    
    @GetMapping("/user/list")	
    public String list(Model model) {
    	model.addAttribute("users", userRepository.findAll());	
    	return "/user/list";
    }    
}
//변경3: PostMapping과 GetMapping의 url 변경
//UserController.java

@Controller
public class UserController {
	@Autowired	
	private UserRepository userRepository;

	@PostMapping("/users")	//1.
	public String create(User user) {
    	System.out.println("user : " + user);
        userRepository.save(user);	
    	return "redirect:/users";	//2.	
    }
    
    @GetMapping("/users")	//1.
    public String list(Model model) {
    	model.addAttribute("users", userRepository.findAll());	
    	return "/user/list";
    }    
}

1. 여러 명의 사용자들에 대한 것이므로 'users'라는 url을 만들어줍니다.

 

2. url이 바뀌었으므로 해당 url도 변경해줍니다.

 

<!--form.html-->

<form action="/create" method="post" action="/users">	<!--1.-->
	<div class="form-group">
    	<label for="userId">사용자 아이디</label>
        <input type="text" class="form-control" name="userId" placeholder="사용자 아이디">
    </div>
    <div class="form-group">
    	<label for="password">Password</label>
        <input type="password" class="form-control" name="password" placeholder="비밀번호">
    </div>
    <div class="form-group">
    	<label for="name">이름</label>
        <input type="text" class="form-control" name="name" placeholder="이름">
    </div>
    <div class="form-group">
    	<label for="email">이메일</label>
        <input type="email" class="form-control" name="email" placeholder="이메일">
    </div>
    <button type="submit" class="btn btn-default">Submit</button>
</form>

1. url을 "/users"로 변경합니다.

 

//변경4: 중복 제거
//UserController.java

@Controller
@RequestMapping("/users")	//1.
public class UserController {
	@Autowired	
	private UserRepository userRepository;

	@PostMapping("")	
	public String create(User user) {
    	System.out.println("user : " + user);
        userRepository.save(user);	
    	return "redirect:/users";	
    }
    
    @GetMapping("")
    public String list(Model model) {
    	model.addAttribute("users", userRepository.findAll());	
    	return "/user/list";
    }    
}

1. PostMapping 과 GetMapping의 url이 '/users'로 동일하기 때문에 중복을 제거해줍니다.

PostMapping의 url: @RequestMapping의 url + @PostMapping의 url = "/users"

GetMapping의 url: @RequestMapping의 url + @GetMapping의 url = "/users"

 

[중복 제거]

1. 중복되는 부분을 include 파일에 따로 분리해줍니다.

<!--중복 제거-->
<!--navigation.html-->

<meta charset="utf-8">
<!--한글 깨짐 해결하기 위해 추가해줌-->
<nav class="navbar navbar-fixed-top header">
	<div class="col-md-12">
		<div class="navbar-header">

			<a href="/" class="navbar-brand">SLiPP</a>
			<button type="button" class="navbar-toggle" data-toggle="collapse"
				data-target="#navbar-collapse1">
				<i class="glyphicon glyphicon-search"></i>
			</button>

		</div>
		<div class="collapse navbar-collapse" id="navbar-collapse1">
			<form class="navbar-form pull-left">
				<div class="input-group" style="max-width: 470px;">
					<input type="text" class="form-control" placeholder="Search"
						name="srch-term" id="srch-term">
					<div class="input-group-btn">
						<button class="btn btn-default btn-primary" type="submit">
							<i class="glyphicon glyphicon-search"></i>
						</button>
					</div>
				</div>
			</form>
			<ul class="nav navbar-nav navbar-right">
				<li><a href="#" class="dropdown-toggle" data-toggle="dropdown"><i
						class="glyphicon glyphicon-bell"></i></a>
					<ul class="dropdown-menu">
						<li><a href="https://slipp.net" target="_blank">SLiPP</a></li>
						<li><a href="https://facebook.com" target="_blank">Facebook</a></li>
					</ul></li>
				<li><a href="/users"><i class="glyphicon glyphicon-user"></i></a></li>
			</ul>
		</div>
	</div>
</nav>
<div class="navbar navbar-default" id="subnav">
	<div class="col-md-12">
		<div class="navbar-header">
			<a href="#" style="margin-left: 15px;"
				class="navbar-btn btn btn-default btn-plus dropdown-toggle"
				data-toggle="dropdown"><i class="glyphicon glyphicon-home"
				style="color: #dd1111;"></i> Home <small><i
					class="glyphicon glyphicon-chevron-down"></i></small></a>
			<ul class="nav dropdown-menu">
				<li><a href="../user/profile.html"><i
						class="glyphicon glyphicon-user" style="color: #1111dd;"></i>
						Profile</a></li>
				<li class="nav-divider"></li>
				<li><a href="#"><i class="glyphicon glyphicon-cog"
						style="color: #dd1111;"></i> Settings</a></li>
			</ul>

			<button type="button" class="navbar-toggle" data-toggle="collapse"
				data-target="#navbar-collapse2">
				<span class="sr-only">Toggle navigation</span> <span
					class="icon-bar"></span> <span class="icon-bar"></span> <span
					class="icon-bar"></span>
			</button>
		</div>
		<div class="collapse navbar-collapse" id="navbar-collapse2">
			<ul class="nav navbar-nav navbar-right">
				<li class="active"><a href="/">Posts</a></li>
				{{^sessionedUser}}
				<!-- #: 존재할 때, ^: 존재하지 않을 때 -->
				>
				<!-- #, ^ 두 가지를 이용하여 if else문 처럼 사용이 가능 ->{{#user}} {{/user}} {{^user}} {{/user}} -->
				<li><a href="/users/login" role="button">로그인</a></li>
				<li><a href="/users/form" role="button">회원가입</a></li>
				{{/sessionedUser}} {{#sessionedUser}}
				<li><a href="/users/logout" role="button">로그아웃</a></li>
				<li><a href="/users/{{id}}/form" role="button">개인정보수정</a></li>
				{{/sessionedUser}}
			</ul>
		</div>
	</div>
</div>
	<!--header.html-->
    
    <meta charset="utf-8">
	<meta http-equiv="content-type" content="text/html; charset=UTF-8">
    <title>SLiPP Java Web Programming</title>
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
    <link href="/css/bootstrap.min.css" rel="stylesheet">
    <!--[if lt IE 9]>
    <script src="//html5shim.googlecode.com/svn/trunk/html5.js"></script>
    <![endif]-->
    <link href="/css/styles.css" rel="stylesheet">
<!--footer.html-->

<!-- script references -->
<script src="/js/jquery-2.2.0.min.js"></script>
<script src="/js/bootstrap.min.js"></script>
<script src="/js/scripts.js"></script>

 

2. mustache 문법을 이용해서 분리한 파일을 필요한 곳에 넣어줍니다.

{{> 파일 경로}}

 

<!--list.html-->

<!DOCTYPE html>
<html lang="kr">
<head>
<meta charset="utf-8">
{{> /include/header}}
</head>
<body>
{{> /include/navigation}}

<div class="container" id="main">
   <div class="col-md-10 col-md-offset-1">
      <div class="panel panel-default">
          <table class="table table-hover">
              <thead>
                <tr>
                    <th>#</th> <th>사용자 아이디</th> <th>이름</th> <th>이메일</th><th></th>
                </tr>
              </thead>
              <tbody>
              	{{#users}}
                <tr>
                    <th scope="row">{{id}}</th>
                    <td>{{userId}}</td> 
                    <td>{{name}}</td>
                    <td>{{email}}</td>
                    <td><a href="/users/{{id}}/form" class="btn btn-success" role="button">수정</a></td>
                </tr>
                {{/users}}
                
              </tbody>
          </table>
        </div>
    </div>
</div>

{{> /include/footer}}
</body>
</html>
반응형