반응형

안녕하세요 무작정 일단 따라 해 보는 Spring 커뮤니티 만들기 5탄 시작합니다.

환경

Eclipse 2019-9 Jee
JDK 1.8_231
Apache Tomcat 8.5.47
MariaDB 10.4.10 
MyBatis 3.2.2
JSTL 1.2
jackson 2.9.4

오늘의 할 

1.유저(user) 테이블 만들기
2.유저(user) 회원가입,로그인 view 만들기
3.유저(user) 회원가입,로그인 백 로직 만들기(값 req,res DB insert)

1.유저(members) 테이블 만들기


제일 먼저 회원가입 기능을 만드려면 DB 테이블을 먼저 만들어야겠죠

 

저희는 MariaDB 10.4 버전을 사용하고 있기때문에

 HeidiSQL 들어가줍니다들어가 줍니다.이제 사용법 아시죠?!

CREATE TABLE `members` (
	`id` INT(11) NOT NULL AUTO_INCREMENT,
	`userId` VARCHAR(64) NULL DEFAULT NULL,
	`password` VARCHAR(256) NULL DEFAULT NULL,
	`nickname` VARCHAR(64) NULL DEFAULT NULL,
	`email` VARCHAR(64) NULL DEFAULT NULL,
	`authority` INT(11) NULL DEFAULT NULL,
	`declaration` INT(11) NULL DEFAULT NULL,
	`last_login` TIMESTAMP NULL DEFAULT current_timestamp() ON UPDATE current_timestamp(),
	`create_time` TIMESTAMP NULL DEFAULT '0000-00-00 00:00:00',
	`update_time` TIMESTAMP NULL DEFAULT '0000-00-00 00:00:00',
	PRIMARY KEY (`id`)
    UNIQUE INDEX `userId` (`userId`)
)

id : 절대 겹치지 않는 구분자 PK

userId : 유저 아이디

password : 유저 비밀번호

nickname : 유저 닉네임

email : 유저 이메일

authority : 권한(관리자, 사용자 등..)

declaration : 신고 횟수

last_login : 마지막 로그인 시간

create_time : 유저 생성한 시간(회원 가입한 시간)

update_time : 비밀번호 업데이트한 시간(n일마다 비밀번호 교체 요구 기능 만들 예정)

UNIQUE INDEX `userId` (`userId`) : 웹 로직을 피해 DB에 데이터를 넣을 경우라도 중복은 피할 수 있게 유니크 키를 넣어줍니다.

 

최종 members 테이블

10.4 UI는 참 이쁘네요 10.2에 비해..


2.유저(members) 회원가입,로그인 view 만들기


views -> user 폴더 생성

views -> user 폴더 -> login.jsp 생성

src/main/java -> controller -> UserController.java 생성

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;

@Controller
@RequestMapping("user/*")
public class UserController {

	
	@RequestMapping(value="user/login",method = RequestMethod.GET)
	public ModelAndView login() {
		ModelAndView mav = new ModelAndView();
		return mav;
	}
	
}

 

 

webapp -> index.jsp 수정

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<jsp:forward page="/user/login"/>    
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>SpringEx01 커뮤니티</title>
</head>
<body>
</body>
</html>

나중에 sitemash를 사용할 때 index.jsp는 적용하기 어렵습니다. 그러므로 jsp:forward를 통해 진입하자마자

/user/login 페이지로 forward 해줍니다.

 

 

login.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script> 
<style>
body {
   font: 13px/20px 'Helvetica Neue', Helvetica, Arial, sans-serif;
   color: #333333;
   background: #596778;
}

.signUp {
   position: relative;
   margin: 50px auto;
   width: 280px;
   padding: 33px 25px 29px;
   background: #FFFFFF;
   border-bottom: 1px solid #C4C4C4;
   border-radius: 5px;
   -webkit-box-shadow: 0 1px 5px rgba(0, 0, 0, 0.25);
   box-shadow: 0 1px 5px rgba(0, 0, 0, 0.25);
}

.signUp:before,
.signUp:after {
   content: '';
   position: absolute;
   bottom: 1px;
   left: 0;
   right: 0;
   height: 10px;
   background: inherit;
   border-bottom: 1px solid #D2D2D2;
   border-radius: 4px;
}

.signUp:after {
   bottom: 3px;
   border-color: #DCDCDC;
}

.signUpTitle {
   margin: -25px -25px 25px;
   padding: 15px 25px;
   line-height: 35px;
   font-size: 26px;
   font-weight: 300;
   color: #777;
   text-align: center;
   text-shadow: 0 1px rgba(255, 255, 255, 0.75);
   background: #F7F7F7;
}

.signUpTitle:before {
   content: '';
   position: absolute;
   top: 0;
   left: 0;
   right: 0;
   height: 8px;
   background: #C4E17F;
   border-radius: 5px 5px 0 0;
   background-image: -webkit-linear-gradient(left, #C4E17F, #C4E17F 12.5%, #F7FDCA 12.5%, #F7FDCA 25%, #FECF71 25%, #FECF71 37.5%, #F0776C 37.5%, #F0776C 50%, #DB9DBE 50%, #db9CBE 62.5%, #C49CDE 62.5%, #C49CDE 75%, #669AE1 75%, #669AE1 87.5%, #62C2E4 87.5%, #62C2E4);
   background-image: -moz-linear-gradient(left, #c4e17f, #C4E17F 12.5%, #F7FDCA 12.5%, #F7FDCA 25%, #FECF71 25%, #FECF71 37.5%, #F0776C 37.5%, #F0776C 50%, #DB9DBE 50%, #DB9CBE 62.5%, #C49CDE 62.5%, #C49CDE 75%, #669AE1 75%, #669AE1 87.5%, #62C2E4 87.5%, #62C2E4);
   background-image: -o-linear-gradient(left, #C4E17F, #C4E17F 12.5%, #F7FDCC 12.5%, #F7FDCA 25%, #FECF71 25%, #FECF71 37.5%, #F0776C 37.5%, #F0776C 50%, #DB9DBE 50%, #DB9DBE 62.5%, #C49CDE 62.5%, #C49CDE 75%, #669AE1 75%, #669AE1 87.5%, #62C2E4 87.5%, #62C2E4);
   background-image: linear-gradient(to right, #C4E17F, #C4E17F 12.5%, #F7FDCA 12.5%, #F7FDCA 25%, #FECF71 25%, #FECF71 37.5%, #F0776C 37.5%, #F0776C 50%, #DB9DBE 50%, #DB9CBE 62.5%, #c49cde 62.5%, #C49CDE 75%, #669AE1 75%, #669AE1 87.5%, #62c2e4 87.5%, #62C2E4);
}

input {
   font-family: inherit;
   color: inherit;
   -webkit-box-sizing: border-box;
   -moz-box-sizing: border-box;
   box-sizing: border-box;
}

.signUpInput {
   width: 100%;
   height: 50px;
   margin-bottom: 25px;
   padding: 0 15px 2px;
   font-size: 17px;
   background: white;
   border: 2px solid #EBEBEB;
   border-radius: 4px;
   -webkit-box-shadow: inset 0 -2px #EBEBEB;
   box-shadow: inset 0 -2px #EBEBEB;
}

.signUpInput:focus {
   border-color: #62C2E4;
   outline: none;
   -webkit-box-shadow: inset 0 -2px #62C2E4;
   box-shadow: inset 0 -2px #62C2E4;
}

.lt-ie9 .signUpInput {
   line-height: 48px;
}

.loginButton {
   position: relative;
   vertical-align: top;
   width: 100%;
   height: 54px;
   padding: 0;
   font-size: 22px;
   color: white;
   text-align: center;
   text-shadow: 0 1px 2px rgba(0, 0, 0, 0.25);
   background: #CCCCFF;
   border: 0;
   border-bottom: 2px solid #D76B60;
   border-radius: 5px;
   cursor: pointer;
   -webkit-box-shadow: inset 0 -2px #D76B60;
   box-shadow: inset 0 -2px #D76B60;
}

.loginButton:active {
   top: 1px;
   outline: none;
   -webkit-box-shadow: none;
   box-shadow: none;
}

.signUpButton {
   position: relative;
   vertical-align: top;
   width: 100%;
   height: 54px;
   padding: 0;
   font-size: 18px;
   color: white;
   text-align: center;
   text-shadow: 0 1px 2px rgba(0, 0, 0, 0.25);
   background: #F0776C;
   border: 0;
   border-bottom: 2px solid #D76B60;
   border-radius: 5px;
   cursor: pointer;
   -webkit-box-shadow: inset 0 -2px #D76B60;
   box-shadow: inset 0 -2px #D76B60;
}

.signUpButton:active {
   top: 1px;
   outline: none;
   -webkit-box-shadow: none;
   box-shadow: none;
}

:-moz-placeholder {
   color: #AAAAAA;
   font-weight: 300;
}

::-moz-placeholder {
   color: #AAAAAA;
   opacity: 1;
   font-weight: 300;
}

::-webkit-input-placeholder {
   color: #AAAAAA;
   font-weight: 300;
}

:-ms-input-placeholder {
   color: #AAAAAA;
   font-weight: 300;
}

::-moz-focus-inner {
   border: 0;
   padding: 0;
}
</style>

<script type="text/javascript">

function loginValidation(){
	
	var userId = $("#userId").val();
	var password = $("#password").val();
	
	if(!userId){
		alert("아이디를 입력하세요.");
		$("#userId").focus();
		return false;
	}else if(!password){
		alert("비밀번호를 입력하세요.");
		$("#password").focus();
		return false;
	}else {
		login(userId,password);
	}
	
}

function login(userId,password){
	
	$.ajax({
		
		url : "/jquery/login",
		type : 'POST',
		data : { userId : userId, 
				password : password	
		},
		success:function(data){
			if(data == 2){
				alert("아이디 혹은 비밀번호가 맞지 않습니다.");
				return false;
			}else if(data == 3){
				location.href="/view/dashboard";
			}
		}
		
	})
	
}

function enterKeyCheck(){
	
 if(event.keyCode == 13)
	  {
	 loginValidation();
	  }
	
	
}

</script>

</head>
<body>

<form class="signUp" id="signupForm">
   <h1 class="signUpTitle">로그인</h1>
   <input type="text" id="userId" class="signUpInput" placeholder="ID" autofocus onkeyup="enterKeyCheck()">
   <input type="password" id="password" class="signUpInput" placeholder="Password" onkeyup="enterKeyCheck()">
   <input type="button" value="로그인" onclick="loginValidation()" class="loginButton">
   <input type="button" value="회원가입" onclick="location.href='/user/signUp'" class="signUpButton">
</form>

</body>
</html>

UI 코드 출처 : 블루비 웹스토어


 

views -> user 폴더 -> signUp.jsp 생성

signUp.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script> 
<meta charset="UTF-8">
<title>회원 가입</title>
<script type="text/javascript">

function signUpValidation(){
	
	var userId = $("#userId").val();
	var userPw = $("#password").val();
	var userPwCheck = $("#passwordCheck").val();
	var nickName = $("#nickname").val();
	var email = $("#email").val();
	
	if(!userId){
		alert("아이디 입력은 필수입니다.");
		$("#userId").focus();
	}else if(!userPw){
		alert("비밀번호 입력은 필수입니다.");
		$("#password").focus();
	}else if(!userPwCheck){
		alert("비밀번호 확인 입력은 필수입니다.");
		$("#passwordCheck").focus();
	}else if(userPw != userPwCheck){
		alert("비밀번호가 맞지 않습니다.");
		$("#userPwCheck").focus();		
	}else if(!nickName){
		alert("닉네임 입력은 필수입니다.");
		$("#nickname").focus();
	}else if(!email){
		alert("이메일 입력은 필수입니다.");
		$("#email").focus();
	}else {
		signUp()
	}
	
}

function signUp(){
	
	$.ajax({
		
		url : "/jquery/signUp",
		type:'POST',
		data :  $("#registerform").serialize(),
		success:function(data){
			if(data == 1){
				alert("회원가입이 완료됐습니다.^^");
				location.href = "/user/login"
			}else if(data == 2){
				alert("이미 존재하는 아이디입니다.");
				return false;
			}else if(data == 3){
				alert("이미 존재하는 닉네임입니다.");
				return false;
			}
		}
		
	})
}

</script>
</head>
<body style="background-color:#f0f5f3">
<form id="registerform">
        <div class="fieldlabel"><label for="userId">*아이디</label></div>
        <div class="formfield"><input type="text" id="userId" name="userId" maxlength="20" value=""></div>
        
        <div class="fieldlabel"><label for="password">*패스워드</label></div>
        <div class="formfield">
<input type="password" id="password" name="password" maxlength="20" autocomplete="off">
</div>

        <div class="fieldlabel"><label for="passwordCheck">패스워드확인</label></div>
        <div class="formfield">
        
<input type="password" id="passwordCheck" name="passwordCheck" maxlength="20" autocomplete="off">
</div>
       
        <div class="fieldlabel"><label for="nickname">*닉네임</label></div>
        <div class="formfield"><input type="text" id="nickname" name="nickname" maxlength="20" value=""></div>

        <div class="fieldlabel"><label for="email">*이메일</label></div>
        <div class="formfield"><input type="text" id="email" name="email" size="20" maxlength="20" 
             value="" autocomplete="off"><span>@</span>
            <input id="domain" list="domains" name="domain" placeholder="도메인입력/선택">
            <datalist id="domains">
                <option value="naver.com">
                <option value="daum.net">
                <option value="gmail.com">
                <option value="yahoo.co.kr">
            </datalist>
        </div>
       
        <div class="btnfield">
            <input type="button" onclick="signUpValidation()" value="회원가입">
        </div>
    </form>
</body>
</html>

 


3.유저(members) 회원가입,로그인 백 로직 만들기


 

src/main/java -> controller -> UserController.java 수정

UserController.java

package com.company01.springEx01.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;

@Controller
@RequestMapping("user/*")
public class UserController {

	
	@RequestMapping(value="user/login",method = RequestMethod.GET)
	public ModelAndView login() {
		ModelAndView mav = new ModelAndView();
		return mav;
	}
	
	@RequestMapping(value="user/signUp",method = RequestMethod.GET)
	public ModelAndView signUp() {
		ModelAndView mav = new ModelAndView();
		return mav;
	}
	
}

 

src/main/java -> controller -> JqueryController.java 수정

JqueryController.java 

package com.company01.springEx01.controller;

import javax.servlet.http.HttpSession;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import com.company01.springEx01.logic.Board;
import com.company01.springEx01.logic.Members;
import com.company01.springEx01.service.BoardService;
import com.company01.springEx01.service.UserService;

@Controller
@RequestMapping("jquery/*")
public class JqueryController {

	@Autowired
	BoardService boardService;
	
	@Autowired
	UserService userService;
	
	@RequestMapping(value="jquery/boardwrite",method = RequestMethod.POST)
	@ResponseBody
	public int boardwrite(Board board) {
		int result = 0; 
		result = boardService.boardwrite(board); 
		return result;
	}
	
	@RequestMapping("jquery/logout")
	public String logout(HttpSession session) {
		session.removeAttribute("loginUser");
		return "/user/login";
	}
	
	@RequestMapping(value="jquery/login",method = RequestMethod.POST)
	@ResponseBody
	public int login(Members members,HttpSession session) {
		int result = 0; 
		String col = null;
		col = "userId";
		Members userIdCheck = userService.getUserOne(members.getUserId(),col);
		if(userIdCheck == null) {
			result = 2;
		}else {
		
		if(members.getUserId().equals(userIdCheck.getUserId())) {
			//ID OK
			if(members.getPassword().equals(userIdCheck.getPassword())) {
				//PW OK 
				session.setAttribute("loginUser", userIdCheck);

				result = 3;
			}else {
				result = 2;
			}
			
		}else {
			//ID not OK
			result = 2;
		}
		}
		
		return result;
	}
	
	@RequestMapping(value="jquery/signUp",method = RequestMethod.POST)
	@ResponseBody
	public int signUp(Members members) {
		int result = 0; 
		String col = null;
		
		col = "userId";
		Members userIdCheck = userService.getUserOne(members.getUserId(),col);
		if(userIdCheck != null) {
		result = 2; 
		}
		
		col = "nickname";
		Members userNicknameCheck = userService.getUserOne(members.getNickname(),col);
		if(userNicknameCheck != null) { result = 3; }	
		
		if(result < 2) {
		result = userService.userJoin(members);	
		}
		
		
		return result;
	}
	
}

login method

Members userIdCheck = userService.getUserOne(members.getUserId(),col);

아이디가 존재하는지 입력값을 보내 DB에서 검사합니다.

존재할 경우 

if(members.getUserId().equals(userIdCheck.getUserId())) { 아이디와 DB에 데이터 아이디와 같은지 확인
//ID OK
if(members.getPassword().equals(userIdCheck.getPassword())) { 비밀번호와 DB에 데이터 비밀번호가 같은지 확인

session.setAttribute("loginUser", userIdCheck); "세션"이라는 것에 로그인한 사용자의 정보를 담음


src/main/java -> services -> UserService.java (interface) 생성

UserService.java (interface)

package com.company01.springEx01.service;

import com.company01.springEx01.logic.Members;

public interface UserService {

	Members getUserOne(String common, String col);

	int userJoin(Members members);

}

 

src/main/java -> services -> UserServiceImpl.java 생성

UserServiceImpl.java 

package com.company01.springEx01.service;

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

import com.company01.springEx01.dao.UserDAO;
import com.company01.springEx01.logic.Members;

@Service
public class UserServiceImpl implements UserService {

	@Autowired
	UserDAO userDAO;

	@Override
	public Members getUserOne(String common,String col) {
		return userDAO.getUserOne(common,col);
	}

	@Override
	public int userJoin(Members members) {
		return userDAO.userJoin(members);
	}
	
}

 

src/main/java -> dao-> UserDAO.java

UserDAO.java

package com.company01.springEx01.dao;

import java.util.HashMap;

import org.apache.ibatis.session.SqlSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import com.company01.springEx01.logic.Members;

@Repository
public class UserDAO {

	@Autowired
	public SqlSession sqlSession;

	public Members getUserOne(String common, String col) {
		HashMap<String, Object> map = new HashMap<String, Object>();
		if(col.equals("userId")) {
			map.put("userId",common);
		}else if(col.equals("nickname")) {
			map.put("nickname",common);
		}
		return sqlSession.selectOne("getUserOne",map);
	}

	public int userJoin(Members members) {
		return sqlSession.insert("userJoin",members);
	}
	
}

 

src/main/java -> logic -> Members.java

Members.java

package com.company01.springEx01.logic;

import java.util.Date;

public class Members {

	private int id;
	private String userId;
	private String password;
	private String nickname;
	private String email;
	private int authority;
	private int declaration;
	private Date last_login;
	private Date create_time;
	private Date update_time;
	
	private String domain;
	
	get../set..
	
	
}

 

혹시 get/set 설정 모르시는 분들을 위한 설명

get/set 만들 클래스를 열은 상태에서 -> 이클립스에서 상단 메뉴 Source -> Generate and Setters... 클릭

Select All 버튼 클릭 -> Generate

 

 

src/main/resources -> mapper 폴더 -> user-Mapper.xml 생성

user-Mapper.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="mapper.user-Mapper">

<select id="getUserOne" resultType="members">
SELECT * FROM members 
<if test="userId != null">
where userId = #{userId};
</if>
<if test="nickname != null">
where nickname = #{nickname};
</if>
</select>

<insert id="userJoin">
insert into members (id,userId,password,nickname,email,authority,last_login,create_time,update_time)
values (#{id},#{userId},#{password},#{nickname},#{email},1,#{last_login},now(),#{update_time})
</insert>

</mapper>

 

 

spring -> mybatis 폴더 -> mybatis-config.xml 수정

mybatis-config.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 alias="board" type="com.company01.springEx01.logic.Board"/>
        <typeAlias alias="members" type="com.company01.springEx01.logic.Members"/>
    </typeAliases>

    <mappers>
        <mapper resource="mapper/board-Mapper.xml"/>
        <mapper resource="mapper/user-Mapper.xml"/>
    </mappers>
</configuration>

 

views -> view -> dashboard.jsp 수정

dashboard.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ include file="/WEB-INF/views/jstlHeader.jsp" %>
<!DOCTYPE html>
<html>
<head>
   
<meta charset="UTF-8">
<title>dashboard</title>
<style>
  table {
    width: 100%;
    border: 1px solid #444444;
  }
  th, td {
    border: 1px solid #444444;
  }
</style>
</head>
<body>
<p>환영합니다 ${sessionScope.loginUser.nickname }님 <a href="/jquery/logout">로그아웃</a></p>
<p>dashboard</p>
<div>게시글 리스트</div>
<table>
<thead><tr>
<td>제목</td>
<td>조회수</td>
<td>좋아요</td>
<td>첨부파일</td>
<td>글 작성 날짜</td>
</tr></thead>

<c:forEach var="b" items="${result }">
<fmt:formatDate value="${b.create_time}" pattern="yyyy-MM-dd HH:MM:ss" var="dateFormat_cr"/>
<tr>
<td><a href="/view/boardDetail?id=${b.id }">${b.subject }</a></td>
<td>${b.views }</td>
<td>${b.likes }</td>
<td>${b.attachments }</td>
<td>${dateFormat_cr }</td>
</tr>
</c:forEach>
</table>
<div> <a href="/view/boardwrite">글 작성하기</a></div>
</body>
</html>

 

${sessionScope.loginUser.nickname} "세션"에 담긴 닉네임 정보가 잘 나왔나 확인하는 작업

 

 

정리

1.signUp.jsp - 회원가입 페이지 뷰

-signUp Method POST 회원가입 사용자 등록 메서드

 

2.login - 로그인 페이지 뷰

-login Method POST 로그인 성공/실패 여부

 

3.logout Method - 세션에 담긴 로그인 정보를 삭제함으로써 로그아웃 기능을 제공함.

 

 

이제 감 잡으신 분들도 있겠지만 이 방식만 외우세요!

1.jsp 데이터 넘기거나 조회 (request or response)

2.Controller에서 받음

3.Controller에서 Service에게 요청

4.ServiceImpl이 받음

5.DAO가 받음

6.DAO가 DB에게 데이터 요청

7. 다시 리턴~jsp까지 전달

 

8. 설정은 XML 파일이 한다. 인식해주는 것, 새로운 것을 등록하는 것, 뭔가 바꿔주는 것

 

어떠한 기능이든 이 방식을 따릅니다. 그 과정이 복잡해지는 거지 그 방식은 똑같습니다.


페이지 뷰


로그인

회원가입

대시보드(수정)

 

 

UI가 뒤죽박죽인 건 나중에 부트스트랩+sitemash을 이용해 다시 작업할 것입니다.

다음 글은 로그인을 만들었으니 게시판 글쓴이,신고 등 유저+게시판을 이용한 작업을 진행하겠습니다.

 

최종 Project Explorer


이제 길어져서 한 번에 못 찍네요...

반응형

+ Recent posts