|
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에 포함된 변수 |
Back-End/Data Base 2019. 7. 8. 18:09
Back-End/Spring 2019. 7. 8. 17:36
실습예제 (기본설정)
회원가입, 로그인, 로그아웃
이번에는 타임리프 템플릿을 사용하지 않고 view를 jsp로 사용할 예정
1) 프로젝트 생성 : Spring Starter Project
프로젝트 이름 : spring04_mongodb
Package : com.example.spring04
2) 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 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 | <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.example</groupId> <artifactId>spring04_mongodb</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>spring04_mongodb</name> <description>Demo project for Spring Boot</description> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.0.2.RELEASE</version> <relativePath /> <!-- lookup parent from repository --> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> </properties> <dependencies>
<!-- spring boot auto restart (설정, 클래스가 바뀌면 auto restart) --> <!-- 스프링부트에서는 소스코드가 바뀌어도 자동으로 서버가 재시작하지 않기 때문에 이 구문을 추가해서 자동으로 재시작하게 해준다. --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <optional>true</optional> </dependency> <!-- mybatis와 스프링 연동 라이브러리 --> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>1.3.2</version> </dependency> <!-- 스프링 부트 라이브러리 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- MYSQL --> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <!-- Mogno DB --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-mongodb</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <!-- 이번 프로젝트에서는 jsp를 사용할 예정이기 때문에 이 코드를 추가해주었다. --> <!-- JSP / JSTL --> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> </dependency>
<!--내장형 톰캣을 사용하기 때문에 적는 구문 --> <dependency> <groupId>org.apache.tomcat.embed</groupId> <artifactId>tomcat-embed-jasper</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project> | cs |
Spring04MongodbApplication.java (스프링부트 프로젝트가 시작되는 메인메소드가 있는 파일) | package com.example.spring04; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication //스프링부트 시작 어노테이션 public class Spring04MongodbApplication { //메인메소드 이 java파일에서 프로젝트가 실행이된다. public static void main(String[] args) { SpringApplication.run(Spring04MongodbApplication.class, args); } } | cs |
application.properties 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 | server.port = 80 ##톰캣포트는 다른 포트번호와 겹치지 않게 써야한다.## ## View Path Config ## #jsp를 쓰기위한 mvc설정 (prefix와 suffix)# spring.mvc.view.prefix=/WEB-INF/views/ spring.mvc.view.suffix=.jsp #jsp auto restart #jsp 페이지의 소스가 바뀌면 자동으로 서버가 다시시작되게끔 하는 코드# server.servlet.jsp.init-parameters.development=true spring.devtools.livereload.enabled=true # static resource #리소스 파일 (css,js)등의 경로# spring.mvc.static-path-pattern=/res/** # custom error page #에러가 발생했을 경우 내가 만든 에러페이지를 보여줄 것인가에 대한 옵션# server.error.whitelabel.enabled=false ## MongoDB Config ## #MongoDB의 포트번호, 데이터베이스 이름, 계정아이디, 비밀번호# spring.data.mongodb.uri=mongodb://localhost:27017 spring.data.mongodb.database=web spring.data.mongodb.username=web spring.data.mongodb.password=1234 | cs |
MongoConfig.java (application.properties에서 설정한 MongoDB에 정보를 읽어서 Bean을 생성하는 페이지) 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 | package com.example.spring04.config; import java.util.Arrays; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.mongodb.config.AbstractMongoConfiguration; import org.springframework.data.mongodb.core.MongoTemplate; import com.mongodb.MongoClient; import com.mongodb.MongoCredential; import com.mongodb.ServerAddress; //application.properties에서 설정한 MongoDB에 정보를 읽어서 Bean을 생성하는 페이지 //스프링 부트에서는 servlet-context, root-context가 없기 때문에 @Configuration //Configuration 어노테이션은 root-context안에 들어갈 코드를 어노테이션으로 만든것이라고 생각하면 된다. public class MongoConfig extends AbstractMongoConfiguration { @Value("${spring.data.mongodb.username}") //application.properties에서 정의한 MongoDB에 계정 아이디 private String userName; @Value("${spring.data.mongodb.password}") //application.properties에서 정의한 MongoDB에 계정 비밀번호 private String password; @Value("${spring.data.mongodb.database}") //application.properties에서 정의한 MongoDB에있는 데이터베이스 private String database; @Override protected String getDatabaseName() { return database; } //레거시 프로젝트에서 xml파일 안에 <bean>태그 안에 있던 코드를 적어놓은것. //mongotemplate을 만들어서 리턴해준다. public @Bean MongoTemplate mongoTemplate() throws Exception { return new MongoTemplate((MongoClient) mongoClient(), database); } @Override public MongoClient mongoClient() { MongoCredential credential = //인증 정보 MongoCredential.createCredential( userName, database, password.toCharArray()); //아이디, 데이터베이스, 비밀번호 return new MongoClient(new ServerAddress("localhost", 27017), Arrays.asList(credential)); } } | cs |
HomeController.java 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | package com.example.spring04.controller; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; @Controller //컨트롤러 빈으로 등록
public class HomeController { // http://localhost까지만 나온다는 뜻, 시작페이지 @RequestMapping("/") public String home() { // /WEB-INF/view/home.jsp return "home"; // home.jsp로 포워딩 //home.jsp페이지가 출력된다. } } | cs |
- jsp를 view로 사용하는 방법 -
jsp를 사용하기 위해서는 추가 작업이 필요하다.
1. src/main 하위에 디렉토리 추가
src/main/webapp
src/main/webapp/WEB-INF
src/main/webapp/WEB-INF/views
2. application.properties 설정
3. pom.xml에서 thymeleaf 라이브러리를 주석처리 한다.
home.jsp 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | <%@ 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" %> <h1>Welcome!</h1> </body> </html> | cs |
header.jsp (스프링부트에서는 jsp를 제외한 것들을 서블릿으로 인식하기 때문에 리소스경로를 지정해야 한다) | <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <!-- core, fmt, functions, jquery, css가 실행될 수 있게끔 포함시킨 header.jsp 페이지 --> <%@ 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" %> <script src="http://code.jquery.com/jquery-3.2.1.js"></script> <link rel="stylesheet" href="/res/css/style.css"> | cs |
style.css | <!--하이퍼링크에 대한 스타일을 지정 --> @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 |
메모장과 방명록을 MongoDB로 구현할 예정
menu.jsp (view) 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 |
회원관리 (회원가입, 로그인, 로그아웃)
MongoDB에서는 PK(기본키) 가 _id로 고정되어 있다.
그렇기 때문에 DTO를 만들때 필드이름을 _id로 해주어야 한다.
================================== 로그인 ==================================
MemberDTO.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 | package com.example.spring04.model.member.dto; public class MemberDTO { private String _id;//mongodb의 Document(레코드에 해당)식별자 private String passwd; private String name; private String email; private String hp; private String zipcode; private String address1; private String address2; //생성자,getter,setter,toString() public MemberDTO() { } public String get_id() { return _id; } public void set_id(String _id) { this._id = _id; } public String getPasswd() { return passwd; } public void setPasswd(String passwd) { this.passwd = passwd; } 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 getHp() { return hp; } public void setHp(String hp) { this.hp = hp; } public String getZipcode() { return zipcode; } public void setZipcode(String zipcode) { this.zipcode = zipcode; } public String getAddress1() { return address1; } public void setAddress1(String address1) { this.address1 = address1; } public String getAddress2() { return address2; } public void setAddress2(String address2) { this.address2 = address2; } @Override public String toString() { return "MemberDTO [_id=" + _id + ", passwd=" + passwd + ", name=" + name + ", email=" + email + ", hp=" + hp + ", zipcode=" + zipcode + ", address1=" + address1 + ", address2=" + address2 + "]"; } } | cs |
MemberDAO.java 생성 | package com.example.spring04.model.member.dao; import com.example.spring04.model.member.dto.MemberDTO; public interface MemberDAO { MemberDTO loginCheck(String userid, String passwd); //로그인 체크 메소드 void join(MemberDTO dto); //회원 가입처리 함수 } | cs |
MemberDAOImpl.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 | package com.example.spring04.model.member.dao; import java.util.List; import javax.inject.Inject; import org.springframework.beans.factory.annotation.Autowired; 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.stereotype.Repository; import com.example.spring04.model.member.dto.MemberDTO;
@Repository //DAO에서 사용하는 어노테이션, Component도 사용가능하다. //sql을 쓸 수 없으므로 함수를 사용해서 명령을 표현
public class MemberDAOImpl implements MemberDAO { //mongodb에 접속하여 명령어를 실행하는 객체 //Autowired 대신에 inject를 써도 된다. //Inject를 사용하려면 pom.xml에 라이브러리를 추가해 주어야 한다. //Inject 어노테이션을 쓰고 우클릭 후 fix Project Setup을 누르고 jar파일에대고 //ok를 누르면 Inject를 사용할 수 있다. //의존성 주입 @Inject //@Autowired private MongoTemplate mongoTemplate; //bean에 MongoTemplate을 리턴하는 메소드가 있었는데 이 메소드가 실행되어야 //Mongo DB를 사용할 수 있기 때문에 의존관계를 주입시키는 것이다. //템플릿을 사용하기 위한 의존성 주입
//mongodb의 컬렉션(테이블에 해당) //그리고 레코드 대신 도큐먼트(document)라고 부르고 사용한다. String COLLECTION_NAME="member";
//로그인 체크 @Override public MemberDTO loginCheck(String userid, String passwd) { // _id : Document(레코드에 해당)의 식별자 Query query=new Query(new Criteria("_id").is(userid)//키값 (_id)가 userid와 같고, .and("passwd").is(passwd)); //passwd와 passwd(입력한값)이 같은지 확인 //mongoTemplate.find(쿼리, 리턴자료형, 컬렉션이름) //리스트가 리턴되므로 get(0) 첫번째 Document만 리턴 List<MemberDTO> list=mongoTemplate.find(query , MemberDTO.class,COLLECTION_NAME); //COLLECTION_NAME는 테이블이름이고, 위의 결과가 참이되면 //DTO에다 아이디와 비밀번호를 저장한다. //만약 list가 0보다 크면 1개만 출력되고 아니면 null이 출력된다. if(list.size() > 0) { return list.get(0); }else { return null; } } //회원가입 처리 //insert쿼리라고 생각하면 된다. @Override public void join(MemberDTO dto) { //Document가 생성됨(insert) //dto안에 들어있는 값을 COLLECTION_NAME 컬렉션(테이블)에 저장한다는 의미 mongoTemplate.insert(dto, COLLECTION_NAME); } } | cs |
MemberService.java | package com.example.spring04.service.member; import com.example.spring04.model.member.dto.MemberDTO; public interface MemberService { MemberDTO loginCheck(String userid, String passwd); void join(MemberDTO dto); //dao를 호출하기위한 메소드 } | cs |
MemberServiceImpl.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 | package com.example.spring04.service.member; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import com.example.spring04.model.member.dao.MemberDAO; import com.example.spring04.model.member.dto.MemberDTO; @Component //빈에 등록 public class MemberServiceImpl implements MemberService { @Autowired //의존성 주입 private MemberDAO memberDao; @Override public MemberDTO loginCheck(String userid, String passwd) { return memberDao.loginCheck(userid, passwd); } @Override public void join(MemberDTO dto) { memberDao.join(dto); } } | cs |
MemberController.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 | package com.example.spring04.controller; import java.util.HashMap; import java.util.Map; import javax.servlet.http.HttpSession; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.servlet.ModelAndView; import com.example.spring04.model.member.dto.MemberDTO; import com.example.spring04.service.member.MemberService; @Controller //컨트롤러 빈으로 설정 @RequestMapping("/member/*") //공통적인 URL 매핑 public class MemberController { @Autowired //의존성주입 (스프링프레임워크에서 지원하는 어노테이션) private MemberService memberService; @RequestMapping("login.do") //세부적인 매핑 public ModelAndView login() { return new ModelAndView("member/login"); //login.jsp로 이동 } | cs |
home.jsp (view) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | <%@ 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" %> <h1>Welcome!</h1> <c:if test="${sessionScope.userid != null}"> <!-- 만약 세션에 유저의 아이디가 저장되어 있으면 방문을 환영한다는 메시지 출력 --> <h2>${sessionScope.name}(${sessionScope.userid})님의 방문을 환영합니다. </h2> </c:if> </body> </html> | cs |
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 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 | <%@ 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>로그인 페이지</title> <!-- 로그인 페이지 --> <%@ include file="../include/header.jsp" %> <script> $(function(){ //밑에 있는 id가 #btnLogin으로 맵핑되는 함수, 클릭 버튼을 누르면 컨트롤러에 있는 login_check.do로 form1에 저장된 자료를 넘긴다. $("#btnLogin").click(function(){ $("#form1").attr("action","/member/login_check.do"); $("#form1").submit(); }); //밑에 있는 id가 #btnJoin으로 맵핑되는 함수, 클릭 버튼을 누르면 컨트롤러에 있는 join.do라는 새로운 페이지로 이동시킨다. //컨트롤러의 join.do로 이동했다가 회원가입페이지로 이동할 예정 $("#btnJoin").click(function(){ $(location).attr("href","/member/join.do") }); }); </script> </head> <body> <%@ include file="../include/menu.jsp" %> <h2>로그인하세요</h2> <form name ="form1" id="form1" method="post"> <table border="1" style="width: 400px"> <tr> <td>아이디</td> <td><input type="text" name="_id" id = "_id" /></td> <!-- 데이터베이스에 아이디가 _id로 되어있기 때문에 _id로 한다. --> </tr> <tr> <td>비밀번호</td> <td><input type="password" name="passwd" id = "passwd" /></td> <font color="red">${map.message}</font></td> <!--비밀번호가 틀렸을때 되돌아와서 표시할 메시지--> <!-- 비밀번호의 타입을 password로 하고 이름을 passwd로 한다. --> </tr> <tr> <td colspan="2" align="center"> <input type="button" id="btnLogin" value="로그인" /> <!-- 로그인을 버튼을 누르면 id값이 위쪽에 있는 스크립트에 맵핑된다.-> <input type="button" id="btnJoin" value="회원가입" /></td> <!--회원가입 버튼을 누르면 id값이 위쪽에 있는 스크립트에 맵핑된다.--> </td> </tr> </table> </form> </body> </html> | cs |
================================== 회원가입 ==================================
MemberController.java 중 일부 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | @RequestMapping("join.do") public String join() { return "member/join"; //join.jsp 회원가입페이지로 이동 } //회원가입페이지에서 회원가입 내용을 다 작성한뒤 버튼을 누르면 맵핑되는 메소드 //dto에 회원정보를 저장하고, Service에 값을 전달함 @RequestMapping("member_join.do") public String member_join(String _id, String passwd , String name) { MemberDTO dto=new MemberDTO(); dto.set_id(_id); dto.setPasswd(passwd); dto.setName(name); memberService.join(dto); //mongodb에 insert됨 return "redirect:/member/login.do"; //로그인 화면으로 이동 } | cs |
join.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"%> <!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> <!-- 유저의 아이디와 비밀번호, 이름을 작성하고 확인 버튼을 누르면 컨트롤러의 member_join.do로 맵핑된다. --> <form method="post" action="${path}/member/member_join.do"> 아이디 : <input name="_id"><br> 비번 : <input type="password" name="passwd"><br> 이름 : <input name="name"><br> <input type="submit" value="확인"> </form> </body> </html> | cs |
MemberServiceImpl.java | @Override public void join(MemberDTO dto) { //회원가입 메소드 memberDao.join(dto); } | cs |
MemberDAOImpl.java | //회원가입 처리 @Override public void join(MemberDTO dto) { //Document가 생성됨(insert) //mongoDB에 member이라는 컬렉션에 사용자가 입력한 값이 들어가게 된다. mongoTemplate.insert(dto, COLLECTION_NAME); }
| cs |
================================== 로그아웃 ==================================
view에서 로그아웃 버튼을 누르면 컨트롤러로 맵핑되어서 세션정보를 초기화하고 다시 로그인 페이지로 이동한다.
MemberController.java | @RequestMapping("logout.do") public String logout(HttpSession session) { //세션 정보 초기화 session.invalidate(); //로그인 페이지로 이동 return "redirect:/member/login.do"; } | cs |
Back-End/Data Base 2019. 7. 8. 12:17
- MongoDB 문법 -
db.memo.count( ) //db안에 들어가 있는 객체들의 갯수를 확인 ( 객체와 그 객체에 대한 속성값을 3번 삽입했으므로 3이 출력된다)
삭제할때는 memo.remove({_id : 2})
// member Collection에 자료 입력 db.member.save( {_id : "kim", passwd : "1234", name : "김철수" } )
// 컬렉션 생성 (테이블에 해당됨) 테이블을 미리 만들고 작업할 수도 있지만 궂이 먼저 만들지 않고 아래 코드처럼 데이터를 입력하면서 만들 수도 있다. db.createCollection("customers")
// 데이터를 입력하면서 동시에 collection 생성 db.customers.insert( { name : "김철수", age : 22 } )
//컬렉션 목록 show collections db.<collection 이름>.insert(<생성할 데이터>)
//데이터 생성 db.customers.insert( {name : "이철호", age : 25} ) db.customers.insert( {name : "lee", age : 35 } ) db.customers.insert( {name : "hong", age : 45 } ) db.customers.insert( {name : "park", age : 55 } )
//데이터 읽기 db.<collection 이름>.find(<검색 조건>) db.customers.find( {name : "김철수"} )
//데이터 수정 db.<collection 이름>.update(<업데이트할 데이터선택>,<데이터를 입력>)
//수정 확인 db.customers.find( )
//데이터 삭제 db.<collection 이름>.remove(<삭제할 데이터 선택>) db.customers.remove( {name : "kim" } ) db.customers.find( )
//데이터 조회 db.customers.find( ) db.<Collection 이름>.find({ }, {"<표시할 field>" : 1, "<표시하지 않을 field>" : 0}) db.customers.find({ }, {"_id" : 0, "name" : 1})
//db.<collection 이름>.find().limit(<보여주고 싶은 데이터 개수>) db.customers.find().limit(1)
//db.<collection 이름>.find().skip(<건너뛰고 싶은 데이터 행수>) db.customers.find().skip(2)
//db.<collection 이름>.find().sort("<정렬에 사용할 기준 field>" : <1 혹은 -1>), 1과 -1은 오름차순과 내림차순을 구분할때 사용한다. db.customers.find().sort({"age" : 1}) //오름차순 정렬 db.customers.find().sort({"age" : -1}) //내림차순 정렬
//함수 여러개 호출 가능 db.customers.find().skip(1).limit(2) //하나를 건너뛰고 2개만 찾으라는 의미
//정확히 일치하는 자료를 검색 db.<collection 이름>.find({"<검색할 field>" : <찾을 값>}) db.customers.find({"age" : 25})
//Less Than Equals 검색 db.<collection 이름>.find({"<검색할 field>" : {"$lte" : <기준 값>}}) db.customers.find({"age" : {$lte : 20}}) //20보다 작거나 같은 나이를 검색
//Greater Than 검색 db.<collection 이름>.find({"<검색할 field>" : {"$gt" : <기준 값>}}) db.customers.find({"age" : {$gt : 25}}) //25보다 큰 나이를 검색
//Greater Than Equals 검색 db.<collection 이름>.find({"<검색할 field>" : {"$gte" : <기준 값>}}) db.customers.find({"age" : {$gte : 25}})
//Not Equals 검색 db.<collection 이름>.find({"<검색할 field>" : {"$ne" : <기준 값>}}) db.customers.find({"age" : {$ne : 25}})
//And 조건 db.<collection 이름>.find({$and : ["<검색할 field>" : {"<검색할 field>"} , {"<검색할 field>" : <기준 값>}]}) db.customers.find($and : [{"age" : {$gte : 23}}, {"name" : "park"}]) //나이가 23보다 크거나 같으면서 이름이 park라는 사람을 찾는 구문
//Or 조건 db.<collection 이름>.find({$or : ["<검색할 field>" : {"<검색할 field>"}, {"<검색할 field>" : "<기준 값>"}]}) db.customers.find({$or : [{"age" : {$gte : 23}}, {"name" : "park"}]}) //나이가 23보다 크거나 같고 or 이름이 park인 사람 찾는 구문
|
-sql과의 비교 (mongoDB는 기본적으로 SQL문법을 사용하지 않는다)-
★Mongo DB에서는 Primary Key (기본키)를 _id라고 써야한다.
Insert
SQL : insert into users ("name",city) values ("terry","seoul")
Mongo DB : db.users.insert({id : "terry", city : "seoul"}) // { }중괄호 안에는 제이슨 문법
Select
SQL : select * from users where id = "terry"
Mongo DB : db.users.find({_id : "terry"})
Update
SQL : update users set city = "busan" where _id = "terry"
Mongo DB : db.users.update ({_id : "terry"}), {$set : {city : "Busan"}}) //id가 terry인것을 찾아서 city를 Busan으로 바꾸라는 쿼리
Delete
SQL : delete from users where _id = "terry"
Mongo DB : db.users.remove({_id : "terry"})
|
-DB 목록-
show dbs (현재 사용중인 데이터베이스 목록을 보여줌)
-db 생성-
use testdb (testdb 데이터베이스를 만들고 testdb데이터베이스를 사용한다)
-현재 사용중인 db 이름-
db
-전체 데이터베이스 목록-
show dbs (현재 testdb 데이터베이스를 사용하고 있으므로, 그 안에 있는 데이터베이스들을 보여준다)
|
Back-End/Spring 2019. 7. 8. 09:28
Spring와 MongoDB 연동
NoSQL
Not Only SQL : SQL만을 사용하지 않는 데이터베이스 관리 시스템
기존의 RDBMS의 한계를 극복하기 위해 만들어진 새로운 형태의 데이터저장소
RDBMS처럼 고정된 스키마가 존재하지 않으며 join을 사용할 수 없음
비정형 데이터를 저장하기 위해 최적화된 저장 방법을 제공함
현실 세계의 모든 데이터가 일정한 틀과 형태를 가지고 있지는 않다.
대화, 채팅, 음악 등
테이블을 만드는 것은 공통적인 속성들을 선택하는 작업
종류 - MongoDB, Cassandra, Redis 등
MongoDB
1) 개요
NoSQL로 분류되는 Cross Flatform Document 지향 데이터베이스 시스템
전통적인 테이블 - 관계 기반의 RDBMS처럼 스키마가 고정된 구조가 아닌 JSON 형태의 동적 스키마형 문서를 사용함
* 몽고DB 사용 예 - 이베이, 뉴욕 타임즈 등
Collection 안에 Document 데이터 저장
Document는 일정한 틀을 가지지 않음
Document 내부의 Field 자료형 형식이 달라도 입력이 가능하며 각 Document들은 모두 일관된 Field를 가지지 않아도 된다.
Table => Collection
Record => Document (문서)
2) 설치
http://mongodb.com
C++로 작성된 오픈소스 문서지향 (Document Oriented) Cross-platform 데이터베이스
Products > MongoDB Server > MongoDB Community Server 다운로드
|
1. https://www.mongodb.com/download-center/community 접속
2. Windows 64-bit x64 버전 설치
3. 다운받은 실행파일을 실행해서 Complete로 설치 (기본적인 옵션으로 설치)
4. Install MongoDB Compass에 체크를 해제 하고 Next버튼 클릭
3) 실행
mongod.exe 서버 실행 파일
mongo.exe 쉘 프로그램
1. c:\data\db 디렉토리 생성 (몽고db에서 기본적으로 참조하는 디렉토리)
(변경하려면 mongod --dbpath "c:\mongodb\data\db")
2. cmd 창을 켜서 cd C:\Program File\MongoDB\Server\4.0\bin (mongodb가 설치된 디렉토리) 를 검색하고, mongod를 쳐서 서버를 실행
이 창이 켜져있어야만 서버가 켜져있는 것이기 때문에 MongoDB를 사용할 수 있다.
3. cmd창을 하나 더 열고, 아까와 같은 MongoDB의 경로를 입력하고, mongo를 치면 mongo.exe 쉘 프로그램이 실행된다.
-sql과의 비교 (mongoDB는 기본적으로 SQL문법을 사용하지 않는다)-
★Mongo DB에서는 Primary Key (기본키)를 _id라고 써야한다.
Insert
SQL : insert into users ("name",city) values ("terry","seoul")
Mongo DB : db.users.insert({id : "terry", city : "seoul"}) // { }중괄호 안에는 제이슨 문법
Select
SQL : select * from users where id = "terry"
Mongo DB : db.users.find({_id : "terry"})
Update
SQL : update users set city = "busan" where _id = "terry"
Mongo DB : db.users.update ({_id : "terry"}), {$set : {city : "Busan"}}) //id가 terry인것을 찾아서 city를 Busan으로 바꾸라는 쿼리
Delete
SQL : delete from users where _id = "terry"
Mongo DB : db.users.remove({_id : "terry"})
|
방금 실행한 mongo cmd창을 키고 다음의 명령을 실행
-DB 목록-
show dbs (현재 사용중인 데이터베이스 목록을 보여줌)
-db 생성-
use testdb (testdb 데이터베이스를 만들고 testdb데이터베이스를 사용한다)
-현재 사용중인 db 이름-
db
-전체 데이터베이스 목록-
show dbs (현재 testdb 데이터베이스를 사용하고 있으므로, 그 안에 있는 데이터베이스들을 보여준다)
|
MongoDB에서는 create 명령어를 사용하지 않는다.
무언가를 처음으로 저장할 때 생성된다.
먼저 스키마 (테이블안에 있는 속성같은 것들) 을 정의할 필요없이 바로 자료를 넣어주면 거기에 맞는 속성이 자동으로 생성된다.
(예를들면 자료를 넣을때 테이블을 한번에 만들 수 있다)
* memo Collection (테이블)에 자료를 입력
// _id : 기본키, 지정하지 않으면 Document 객체의 번지값으로 저장됨
db.memo.save ( {_id : 1, writer : "김철수", memo : "첫번째 메모", post_date : new Date( ) } )
db.memo.save ( {_id : 2, writer : "홍철수", memo : "두번째 메모", post_date : new Date( ) } )
db.memo.save ( {writer : "박철수", memo : "세번째 메모", post_date : new Date( ) } ) //id값을 넣지 않았기 때문에 Document객체의 번지값으로 자동저장 된다.
db.memo.find( ) //자료를 넣은 테이블을 확인할 때 사용
값을 넣을때 나오는 nUpserted는 insert와 update를 합친말로 넣고, 최신화한다는 의미이고,
세번째 값은 id를 따로 넣어주지 않았기 때문에 id 키 값이 Document 객체의 번지값으로 자동으로 저장이 된다.
MongoDB는 비정형의 자료를 저장하기 적합한 구조이다.
- MongoDB 문법 -
db.memo.count( ) //db안에 들어가 있는 객체들의 갯수를 확인 ( 객체와 그 객체에 대한 속성값을 3번 삽입했으므로 3이 출력된다)
삭제할때는 memo.remove({_id : 2})
// member Collection에 자료 입력 db.member.save( {_id : "kim", passwd : "1234", name : "김철수" } )
// 컬렉션 생성 (테이블에 해당됨) 테이블을 미리 만들고 작업할 수도 있지만 궂이 먼저 만들지 않고 아래 코드처럼 데이터를 입력하면서 만들 수도 있다. db.createCollection("customers")
// 데이터를 입력하면서 동시에 collection 생성 db.customers.insert( { name : "김철수", age : 22 } )
//컬렉션 목록 show collections db.<collection 이름>.insert(<생성할 데이터>)
//데이터 생성 db.customers.insert( {name : "이철호", age : 25} ) db.customers.insert( {name : "lee", age : 35 } ) db.customers.insert( {name : "hong", age : 45 } ) db.customers.insert( {name : "park", age : 55 } )
//데이터 읽기 db.<collection 이름>.find(<검색 조건>) db.customers.find( {name : "김철수"} )
//데이터 수정 db.<collection 이름>.update(<업데이트할 데이터선택>,<데이터를 입력>)
//수정 확인 db.customers.find( )
//데이터 삭제 db.<collection 이름>.remove(<삭제할 데이터 선택>) db.customers.remove( {name : "kim" } ) db.customers.find( )
//데이터 조회 db.customers.find( ) db.<Collection 이름>.find({ }, {"<표시할 field>" : 1, "<표시하지 않을 field>" : 0}) db.customers.find({ }, {"_id" : 0, "name" : 1})
//db.<collection 이름>.find().limit(<보여주고 싶은 데이터 개수>) db.customers.find().limit(1)
//db.<collection 이름>.find().skip(<건너뛰고 싶은 데이터 행수>) db.customers.find().skip(2)
//db.<collection 이름>.find().sort("<정렬에 사용할 기준 field>" : <1 혹은 -1>), 1과 -1은 오름차순과 내림차순을 구분할때 사용한다. db.customers.find().sort({"age" : 1}) //오름차순 정렬 db.customers.find().sort({"age" : -1}) //내림차순 정렬
//함수 여러개 호출 가능 db.customers.find().skip(1).limit(2) //하나를 건너뛰고 2개만 찾으라는 의미
//정확히 일치하는 자료를 검색 db.<collection 이름>.find({"<검색할 field>" : <찾을 값>}) db.customers.find({"age" : 25})
//Less Than Equals 검색 db.<collection 이름>.find({"<검색할 field>" : {"$lte" : <기준 값>}}) db.customers.find({"age" : {$lte : 20}}) //20보다 작거나 같은 나이를 검색
//Greater Than 검색 db.<collection 이름>.find({"<검색할 field>" : {"$gt" : <기준 값>}}) db.customers.find({"age" : {$gt : 25}}) //25보다 큰 나이를 검색
//Greater Than Equals 검색 db.<collection 이름>.find({"<검색할 field>" : {"$gte" : <기준 값>}}) db.customers.find({"age" : {$gte : 25}})
//Not Equals 검색 db.<collection 이름>.find({"<검색할 field>" : {"$ne" : <기준 값>}}) db.customers.find({"age" : {$ne : 25}})
//And 조건 db.<collection 이름>.find({$and : ["<검색할 field>" : {"<검색할 field>"} , {"<검색할 field>" : <기준 값>}]}) db.customers.find($and : [{"age" : {$gte : 23}}, {"name" : "park"}]) //나이가 23보다 크거나 같으면서 이름이 park라는 사람을 찾는 구문
//Or 조건 db.<collection 이름>.find({$or : ["<검색할 field>" : {"<검색할 field>"}, {"<검색할 field>" : "<기준 값>"}]}) db.customers.find({$or : [{"age" : {$gte : 23}}, {"name" : "park"}]}) //나이가 23보다 크거나 같고 or 이름이 park인 사람 찾는 구문
|
MongoDB 인증 설정
1) 관리자 계정 만들기
use admin
db.createUser( { user : "admin", pwd : "1234", roles : [ {role : "userAdminAnyDatabase", db : "admin"} ] })
//아이디는 admin으로 하고, 비밀번호는 1234로 하고 사용권한을 설정해서 admin(관리자) 로 한다는 구문이다. //userAdminAnyDatabase는 admin이라는 계정에 데이터베이스에 모든권한을 위임한다는 의미이다.
|
admin 데이터베이스가 생성되고 admin 관리자 계정이 생성된다.
사용권한 참조 https://docs.mongodb.com/manual/core/authorization/
Ctrl + C를 눌러서 mongod.exe 와 mongo.exe 프로그램을 종료시킴
mongoDB 서버 인증모드로 재시작 (아이디와 패스워드를 치고 들어가기 위해 하는것)
재시작 후에 mongod --auth로 서버를 킨다.
다른 cmd창을 켜서 방금 만든 관리자 계정으로 접속한다.
-관리자 계정으로 로그인 해보기-
1. mongo --port 27017 -u "admin" -p "1234" --authenticationDatabase "admin" // (포트번호, 아이디, 비밀번호, 데이터베이스 이름) mongo에 접속하면서 아이디와 비밀번호를 같이 보내서 접속
2. mongo로 접속한 후에 use admin db.auth("admin","1234")
=> 1이 출력되면 인증이 성공
|
2) 일반사용자 계정 만들기
use web db.createUser( { user:"web", pwd:"1234", roles:[ {role:"readWrite", db:"web"}, {role:"read", db:"reporting"} ] })
//web라는 아이디와 1234 비밀번호를 가진 계정을 만든다. //이 계정은 web 데이터베이스에 관해서는 읽고 쓰기가 가능하고, reporting 데이터베이스에 관해서는 읽기만 가능하다.
|
데이터베이스마다 다른 권한을 부여할 수 있음
web 데이터베이스는 읽기 + 쓰기 가능
reporting 데이터베이스는 읽기만 가능
일반 사용자 계정으로 전송
-일반 사용자 계정으로 로그인 해보기-
다른 cmd창을 켜서 방금 만든 일반 사용자 계정으로 접속한다. 두가지 방법이 있다.
1. mongo --port 27017 -u "web" -p "1234" --authenticationDatabase "web" // (포트번호, 아이디, 비밀번호, 데이터베이스 이름) mongo에 접속하면서 아이디와 비밀번호를 같이 보내서 접속
2. mongo로 접속한 후에 use web db.auth("web","1234")
=> 1이 출력되면 인증이 성공
|
Back-End/Spring 2019. 7. 7. 22:07
-방명록 만들기-
방명록 관련 sql
데이터베이스에서 쿼리 작성 | create table guestbook ( //gustbook 테이블 생성 idx number not null primary key, //글번호, null값 x, 기본키로 설정 name varchar2(50) not null, //이름, null값 x email varchar2(50) not null, //이메일, null값 x passwd varchar2(50) not null, //비밀번호, null값 x content varchar2(4000) not null, //내용, null값 x post_date date default sysdate //날짜, 기본값으로 설정 (현재날짜로) ); | cs |
시퀀스 만들기 | create sequence guestbook_seq //시퀀스를 생성 start with 1 //시작은 1부터 시작해서 increment by 1 //1씩 증가함 nomaxvalue //무한대로 증가 nocache; //cache를 사용하지 않는 옵션으로 생성 //(그러니까 캐쉬에 저장된 페이지를 불러오는게 아니라 항상 최신에 페이지를 불러오는것) //캐쉬에 저장하면 발급속도는 빠른대신에 서버가 멈추면 캐쉬안에 저장된 값도 날라가기 때문에 //속도가 좀 느리더라도 캐쉬를 사용하지 않는 방법을 선택했다. | cs |
만든 방명록 테이블에 자료 삽입 | insert into guestbook (idx,name,email,passwd,content) values (guestbook_seq.nextval,'kim','kim@nate.com','1234','방명록'); | cs |
위의 쿼리를 다 작성한 후에 작업완료
GuestbookDTO.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 | package com.example.spring03_boot.model.dto; import java.util.Date; public class GuestbookDTO {
private int idx; //글번호 private String name; //이름 private String email; //이메일 private String content; //내용 private String passwd; //비밀번호 private Date post_date; //현재날짜 //java.util.Date //getter,setter, toString() public int getIdx() { return idx; } public void setIdx(int idx) { this.idx = idx; } 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 getContent() { return content; } public void setContent(String content) { this.content = content; } public String getPasswd() { return passwd; } public void setPasswd(String passwd) { this.passwd = passwd; } 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 [idx=" + idx + ", name=" + name + ", email=" + email + ", content=" + content + ", passwd=" + passwd + ", 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 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 | package com.example.spring03_boot.model.dao; import java.util.List; import org.apache.ibatis.annotations.Delete; import org.apache.ibatis.annotations.Insert; import org.apache.ibatis.annotations.Select; import org.apache.ibatis.annotations.Update; import com.example.spring03_boot.MapperScan; import com.example.spring03_boot.model.dto.GuestbookDTO; // mybatis interface mapper (SQL 명령어가 포함된 코드) //인터페이스에는 원래 미완성된 코드 (추상메소드)만 넣을 수 있으나 여기에서는 //sql쿼리 어노테이션을 붙여서 추상메소드를 실행하면 위에 있는 sql쿼리가 실행이 된다. //아까 애플리케이션.java파일에서 MapperScan 어노테이션을 사용해서 //("com.example.spring03_boot.model")경로에 있는 mapper을 사용할 수 있도록 설정해놓았기 때문에 // 여기 있는 sql쿼리를 바로 사용할 수 있는 것이다. //그리고 여기에서 다 구현을 하고 있기 때문에 따로 DAOImpl (인터페이스 구현 클래스)를 만들필요가 없다. public interface GuestbookDAO { @Select("select * from guestbook order by idx desc") // 게시글번호의 내림차순으로 방명록의 모든 요소를 검색 public List<GuestbookDTO> list(); // sql문이 여러줄 있을 경우에는 따움표나 쉼표나 띄어쓰기를 주의해서 사용한다. @Insert("insert into guestbook " // 게시글 생성 (글번호 다음꺼, 이름, 이메일, 비밀번호, 내용) + "(idx,name,email,passwd,content)" + " values " + "(guestbook_seq.nextval, #{name}, #{email}" + ", #{passwd},#{content})") public void insert(GuestbookDTO dto); @Select("select * from guestbook where idx=#{idx}") // 해당 게시글번호에 맞는 게시글의 모든 요소를 검색 public GuestbookDTO view(int idx); @Update("update guestbook set " + " name=#{name}, email=#{email}, content=#{content}" + " where idx=#{idx}") // 글번호에 맞는 게시글의 정보 (이름, 이메일, 내용)을 수정함 public void update(GuestbookDTO dto); @Delete("delete from guestbook where idx=#{idx}") // 게시글 번호에 맞는 게시글을 삭제함 public void delete(int idx); } | cs |
GuestbookService.java 파일 생성 | package com.example.spring03_boot.service; import java.util.List; import com.example.spring03_boot.model.dto.GuestbookDTO; public interface GuestbookService { public List<GuestbookDTO> list(); //게시글 목록 public void insert(GuestbookDTO dto); //게시글 추가 public GuestbookDTO view(int idx); //게시글 상세화면 public void update(GuestbookDTO dto); //게시글 수정 public void delete(int idx); //게시글 삭제 } | cs |
서비스를 구현할 구현 클래스 (GuestbookServiceImpl.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 | package com.example.spring03_boot.service; import java.util.List; import javax.inject.Inject; import org.springframework.stereotype.Service; import com.example.spring03_boot.model.dao.GuestbookDAO; import com.example.spring03_boot.model.dto.GuestbookDTO; @Service //service bean으로 등록 public class GuestbookServiceImpl implements GuestbookService { @Inject //dao를 사용하기 위해 의존성 주입 GuestbookDAO guestbookDao; @Override public List<GuestbookDTO> list() { //게시글 목록 return guestbookDao.list(); } @Override public void insert(GuestbookDTO dto) { //게시글 생성 guestbookDao.insert(dto); } @Override public GuestbookDTO view(int idx) { //게시글 상세화면 return guestbookDao.view(idx); } @Override public void update(GuestbookDTO dto) { //게시글 수정 guestbookDao.update(dto); } @Override public void delete(int idx) { //게시글 삭제 guestbookDao.delete(idx); } } | 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 | package com.example.spring03_boot.controller; import java.util.List; import javax.inject.Inject; 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.spring03_boot.model.dto.GuestbookDTO; import com.example.spring03_boot.service.GuestbookService; @Controller // Controller bean으로 등록 public class GuestbookController { @Inject // 서비스 빈 inject (서비스 객체를 호출하기 위해서 의존성을 주입함) GuestbookService guestbookService; @RequestMapping("list.do") public ModelAndView list(ModelAndView mav) { mav.setViewName("list"); //뷰의 이름 List<GuestbookDTO> list=guestbookService.list(); mav.addObject("list", list); //뷰에 전달할 데이터 return mav; //뷰로 이동 (화면 출력함) } } | cs |
아까는 jsp에서 출력을 했지만 이번에는 템플릿 (list.html을 만들어서) 을 사용할 예정
- 타임리프 활성화 -
지금부터 실습하는 예제는 타임리프 템플릿을 사용함 (jsp파일 대신 출력할 view)
1. application.properties 에서 jsp 뷰 설정을 주석 처리함 (둘 중에 하나만 쓸 수 있기 때문!)
2. pom.xml에서 thymeleaf 라이브러리의 주석을 해제함
3. templates 폴더 하위에 list.html 파일을 작성 주의할점 : 닫는 태그가 있을 경우에는 상관없지만 단독 태그일 경우에는 반드시 끝에 "/" 를 붙여야 한다. ex) <meta charset> 등등 xml 문법을 따르기 때문에 이렇게 해주어야 한다.
list.html 작성 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 | <!DOCTYPE html> <!-- 타임리프 템플릿으로 선언--> <!-- 이 파일은 html이 아니라 템플릿이다. --> <!-- xml형식이라 생각하면 된다 xmlns는 xml의 네임스페이스라는 뜻 --> <!-- 그리고 타임리프 템플릿이라 지정해주는 코드이다. --> <html xmlns:th="http://www.thymeleaf.org"> <head> <!-- 단독태그는 반드시 태그 안쪽에 슬래시 "/" 를 붙여야 한다. --> <meta charset="UTF-8" /> <!-- include="디렉토리/페이지::프레그먼트이름" remove="tag" 바깥쪽 태그 제거 --> <meta th:include="include/header::header" th:remove="tag"></meta> <title>Insert title here</title> <!-- @{/디렉토리/파일} static resource를 참조함 --> <script th:src="@{/js/test.js}"></script> <script> $(function(){ //test(); }); </script> </head> <body> <!-- <img th:src="@{/images/Tulips.jpg}" width="50px" height="50px" /> --> <div>방명록</div> <!-- static resource : @{디렉토리/파일} --> <a href="write.do">방명록 작성</a> <table border="1"> <tr> <th>번호</th> <th>이름</th> <th>내용</th> <th>날짜</th> </tr> <!-- 개별변수:${집합변수} --> <!-- dates.format(날짜데이터, 출력형식) --> <!-- href="view.do?idx=3" --> <!-- th:href="@{}" @{정적인 텍스트(변수=값)} 이라는 뜻이다.--> <tr th:each="row:${list}"> <!-- each는 반복문이라는 뜻이다. 즉 tr구문이 반복된다는 뜻--> <!-- row 옆에 콜론 ":"이 있는데 변수라는 의미이다. --> <!-- 즉 list를 row변수안에 넣는다는 의미 밑에 코드는 row안에 있는 값들을 하나씩 출력하는 것 --> <!-- 컨트롤러에서 변수명을 list라고 넘겼기 때문에 이것을 받기 위해 사용한 구문이다. --> <td><span th:text="${row.idx}"></span></td> <td><span th:text="${row.name}"></span></td> <td> <!-- 변수를 사용할땐 ${}를 쓰고, 리소스는 (클릭하면 view.do라는 리소스로 넘어간다) @{}를 사용한다. --> <a th:href="@{view.do(idx=${row.idx})}"><span th:text="${row.content}"></span> </a> </td> <td> <!-- #dates는 내장함수이고, 날짜를 yyyy-MM-dd HH:mm:ss이런 형식으로 만들겠다는 구문이다.--> <span th:text= "${#dates.format(row.post_date, 'yyyy-MM-dd HH:mm:ss')}"></span></td> </tr> </table> </body> </html> | cs |
아까 application.properties파일에서 기본 에러페이지를 사용하지 않고, 내가 만든 에러페이지를 사용한다고 했었기 때문에
에러페이지를 하나 만들어주어야 한다.
application.properties중 일부 | server.error.whitelabel.enabled=false //기본 에러페이지를 사용하지 않고, 내가 만든 에러페이지를 사용한다는 코드 | cs |
templates폴더 하위에 error.html 파일 작성 | <!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>Insert title here</title> </head> <body> <h3>에러가 발생했습니다.</h3> </body> </html> | cs |
지금 실행하면 jsp로 만들었을때는 메시지가 나올 페이지를 만들었지만, 타임리프 템플릿에서는 메시지가 나올 페이지를 아직 만들지
않았기 때문에 에러가 발생한다. 그래서 메시지를 출력할 타임리프 템플릿을 만들어주어야 한다.
메시지를 출력할 hello.html 파일 작성 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | <!-- templates/hello.html --> <!DOCTYPE html> <!-- xml namespace 지정 --> <html xmlns:th="http://www.thymeleaf.org"> <head> <!-- 단독태그는 안되기 때문에 슬래시 "/"를 붙인다. --> <meta charset="UTF-8" /> <title>Insert title here</title> </head> <body> <!-- th: 타임리프 태그의 요소 --> <!-- th:text="타임리프 변수" 변수값을 텍스트로 출력함 --> <!-- 단독으로 message만 사용하면 값이 나오지 않기 때문에 --> <!-- 반드시 태그 안쪽에 변수를 사용해서 출력하여야 한다. --> <h2>타임리프 템플릿 사용 버전</h2> <span th:text="${message}"></span> </body> </html> | cs |
========================= 정적인 요소들 사용하는 방법 (css, js) =========================
static (리소스는 이 폴더에 넣어야됨) 폴더 하위 css폴더와 js폴더를 각각 만들고 css, js파일 생성
my.css | @charset "UTF-8"; div { color: blue; font-size: 30px; } | cs |
test.js | // static/js/test.js function test(){ alert("자바스크립트 테스트") } | cs |
타임리프 템플릿에 include를 시키고 싶으면 include폴더를 만들고 하위에 header.html 파일을 생성하고 링크시킨다.
header.html 파일 생성 | <!-- 타임리프의 코드 조각 --> <head th:fragment="header"> //다른 파일에 include되는 부분 <script src="http://code.jquery.com/jquery-3.2.1.min.js"></script> <link rel="stylesheet" type="text/css" th:href="@{/css/my.css}" /> //리소스를 추가할때는 @{}를 사용한다. 안에 있는 것은 css파일의 경로 //js파일과 css파일을 include 하겠다는 의미 </head> | cs |
이미지를 넣고 싶을때는 static 디렉토리 하위에 파일을 넣고, 템플릿에서 링크를 걸면 된다.
list.html에 이미지 링크 태그를 추가 | <img th:src="@{/images/Tulips.jpg}" width="50px" height="50px" /> //마찬가지로 jpg도 리소스이기 때문에 @{}형식 안에 출력할 이미지를 넣어주면 된다. | cs |
Back-End/Spring 2019. 7. 7. 20:13
- 타임리프 템플릿 이란? -
템플릿 엔진, th:xx 형식으로 속성을 html 태그에 추가하여 값이나 처리 등을 페이지에 심을 수 있다.
JSP, 그루비 등 다른 템플릿도 스프링 부트에서 사용 가능하지만 타임리프가 가장 많이 쓰인다고 한다.
-타임리프 템플릿 문법 및 표현방법 정리-
th:text
th:text는 태그 안에 들어가는 텍스트 값이다.
<span th:text="${eventFvrDtl.winRnkg}"></span> | cs |
th:if, th:unless, th:value
th:if는 if, th:unless는 else 표현이다.
th:value는 태그 안의 value 이다.
<th:block th:if="${eventPtcpPsbOrdData != null && #lists.size(eventPtcpPsbOrdData.eventPtcpOrdInfoList) > 0}"> <input type="hidden" id="ibx_TotalPurAplAmt" th:value="${totalPurAplAmt}"/> </th:block>
<th:block th:unless="${eventPtcpPsbOrdData != null && #lists.size(eventPtcpPsbOrdData.eventPtcpOrdInfoList) > 0}"> <input type="hidden" id="ibx_TotalPurAplAmt" value="0"/> </th:block>
th:utext (unescaped text)
th:utext는 <div></div> 같은 태그 형식의 코드를 삽입하고 싶을 때 사용한다.
태그형식의 텍스트가 들어올시 태그로 인식한다.
<!-- HTML 컨텐츠 영역 --> <th:block th:utext="${#campaignUtils.unescapeHtml(eventDispTempleteInfo.htmlContents)}"></th:block> cs
th:fagment
include와 비슷하다.
특정 영역을 가져와서 나타낼 수 있다.
예를 들어 페이지마다 각각의 게시판을 가지고 싶은 경우
포함하는 곳.
ex) eventPage1.html
<th:block th:if="${#lists.size(eventDispTemplateCornerList)} > 0" th:each="eventDispTemplateCorner : ${eventDispTemplateCornerList}"> <!-- 이벤트 템플릿 코너 --> <th:block th:include="${eventDispTemplateCorner.cmpnTmplFileUrl} :: corner (${eventDispTemplateCorner.cmpnNo}, ${eventData.eventBaseInfo.eventPtcpPsbYn})"></th:block> </th:block>
받는 곳.
ex) board.html
<th:block th:fragment="corner (cmpnNo, eventPtcpPsbYn)"> <div class="content_title noline"> <p class="title">게시판</p> </div> </th:block>
controller을 거쳐 화면으로 가져온 데이터를 스크립트로 제어할 때
// controller ModelAndView mv; mv.addObject("eventData", eventData); return mv
// controller를 거쳐 화면으로 가져온 데이터를 스크립트로 제어할때 var data1 = [[${eventData}]]; var eventPtcpPsbYn = [[${#strings.defaultString(eventData.eventBaseInfo.eventPtcpPsbYn, 'Y')}]]; cs
태그 안의 attribute를 타임리프로 정의할 때
// 태그 안의 attribute를 타임리프로 정의할때 <div id="myDiv1" th:attr="usemap=|#E_${eventData.eventBaseInfo.cmpnNo}|"> </div> // 정의된 결과 <div id="myDiv1" usemap="#E_21082"> </div>
출처 https://shlee0882.tistory.com/134
Back-End/Spring 2019. 7. 7. 10:18
- 템플릿 엔진이란? -
템플릿 프로세서 (Template Processor)를 사용하여 웹 템블릿 (Web Template)를 결합하여 완성된 웹 페이지를 만들어내는 시스템이다.
자료 (Data) 를 결합하여 페이지를 만들어 내기도 하고 많은 양의 Content를 표현하는 것을 도와준다.
예를 들어 기존의 방식에서는 서버에서 데이터베이스의 데이터를 가져온 뒤 HTML로 만들어 클라이언트에게 보내주었습니다.
이 방식은 페이지의 일부만 변할 때에도 전체 페이지를 다시 그려야 하는 비효율적인 방식이었습니다.
이 때문에 많은 사람들이 Ajax가 나왔을 때 열광했습니다.
Ajax로 요청을 보내면 서버는 요청한 데이터만 주고 프론트엔드단에서 해당 부분만 재가공하여 보여주면 되었습니다.
전의 방식에 비해 서버의 부담을 줄이는 혁신적인 방법이었지만 문제가 끝난것은 아니었습니다.
보통 jquery를 사용하거나 javascript를 사용하여 HTML에 가공된 데이터를 보여주는데 조금의 실수라도 하면
페이지가 보이지 않거나 이상하게 보이는 경우도 있었습니다.
이 때문에 쉬운 표현으로 서버에서 받아온 데이터를 효과적으로 보여줄 중간 매개체를 원하게 되는데
이 역할을 한 것이 바로 템플릿 엔진입니다.
템플릿 엔진을 사용하면 비교적 간단한 표현 (조건문, 변수, 반복문) 을 통해 효과적으로 데이터를 가공하여 웹 페이지를
보여줄 수 있습니다.
-템플릿 엔진을 사용하는 이유-
1. 많은 코드를 줄일 수 있다. (대부분의 Template Engine는 기존의 HTML에 비해서 간단한 문법을 사용합니다)
2. 재사용성이 높다 (똑같은 디자인의 페이지에 보이는 데이터만 바뀔때 Template Engine 문법으로 만들어 놓고 데이터를 바꿔가면서 렌더링 해주면 된다.)
3. 유지보수에 용이하다. (Template Engine을 사용하면 동일한 Template를 사용한다는 전제하에 Template과 넘겨주는 데이터만 수정하면 끝입니다.)
|
|