타닥타닥 개발자의 일상

스프링 부트로 SpringBoot 회원가입, 페이징, 글작성-수정-삭제-답변, 댓글 작성 되는 게시판 페이지 만들기 (자바 스크립트 JS, 자바 Java이용) 본문

코딩 기록/SpringBoot

스프링 부트로 SpringBoot 회원가입, 페이징, 글작성-수정-삭제-답변, 댓글 작성 되는 게시판 페이지 만들기 (자바 스크립트 JS, 자바 Java이용)

NomadHaven 2022. 2. 26. 10:50

기본적 세팅은 아래글

https://developerson.tistory.com/114

페이징은 아래글을 참고해서 만든 게시판이다.

https://developerson.tistory.com/116

 

별도의 설명 없이 우선 코드만 백업할 예정.

이제 이걸 이해하는건 온전히 내 몫이다.

이해가 될때까지 계속 보는수 밖엔 없겠지

Spring Boot 스프링 부트를 이용한 백엔드 폴더 및 파일 구조

DatabaseConfig.java
package mul.camp.a;

import javax.sql.DataSource;

import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;

@Configuration
public class DatabaseConfig {

	@Bean
	public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
		System.out.println("DatabaseConfig sqlSessionFactory");
		
		SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
		sqlSessionFactoryBean.setDataSource(dataSource);
		
		Resource arrResource[] = new PathMatchingResourcePatternResolver().getResources("classpath:sqls/*.xml");
		sqlSessionFactoryBean.setMapperLocations(arrResource);
		sqlSessionFactoryBean.getObject().getConfiguration().setMapUnderscoreToCamelCase(true);
		
		return (SqlSessionFactory)sqlSessionFactoryBean.getObject();		
	}
	
	@Bean
	public SqlSessionTemplate sqlSession(SqlSessionFactory sqlSessionFactory) {
		return new SqlSessionTemplate(sqlSessionFactory);
	}
	
}
SpringBookBackApplication.java
package mul.camp.a;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringBootBackApplication {

	public static void main(String[] args) {
		SpringApplication.run(SpringBootBackApplication.class, args);
	}

}
WebConfig.java
package mul.camp.a;

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class WebConfig implements WebMvcConfigurer {

	@Override
	public void addCorsMappings(CorsRegistry registry) {
		// TODO Auto-generated method stub
		//WebMvcConfigurer.super.addCorsMappings(registry);
		
		//registry.addMapping("/**").allowedOrigins("http://localhost:8090");
		registry.addMapping("/**").allowedOrigins("*"); //모든 경로 모든 곳에서 접속 가능하게 설정
	}

}

 

 

pom.xml
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.6.3</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.example</groupId>
	<artifactId>springBootBack</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>springBootBack</name>
	<description>Demo project for Spring Boot</description>
	<properties>
		<java.version>1.8</java.version>
	</properties>
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
			
		<!--추가된 부분 https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web -->
		<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web/2.6.3 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId> 
</dependency>
		
		<!--추가된 부분 https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-tomcat/2.6.3 -->
		<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-tomcat</artifactId>
</dependency>
		
		<!--추가된 부분 Json library -->
<dependency>
	          <groupId>com.fasterxml.jackson.core</groupId>
	          <artifactId>jackson-core</artifactId>
	          <version>2.10.1</version>
	      </dependency>
	      
	      <dependency>
	          <groupId>com.fasterxml.jackson.core</groupId>
	          <artifactId>jackson-databind</artifactId>
	          <version>2.10.1</version>
	      </dependency>
	      
	      <!-- 추가한 부분 https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-jdbc/2.6.3 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
	      
	      <!-- 추가한 부분 https://mvnrepository.com/artifact/org.mybatis.spring.boot/mybatis-spring-boot-starter/2.2.2 -->
<dependency>
    <groupId>org.mybatis.spring.boot</groupId>
    <artifactId>mybatis-spring-boot-starter</artifactId>
    <version>2.2.0</version>
</dependency>


<!-- 추가한 부분 https://mvnrepository.com/artifact/org.mybatis/mybatis-spring/2.0.7 -->
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis-spring</artifactId>
    <version>2.0.6</version>
</dependency>

<!-- 추가한 부분 https://mvnrepository.com/artifact/org.mybatis/mybatis/3.5.9 -->
<dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis</artifactId>
    <version>3.5.9</version>
</dependency>

<!-- 추가한 부분 https://mvnrepository.com/artifact/com.oracle.database.jdbc/ojdbc6/11.2.0.4 -->
<dependency>
    <groupId>com.oracle.database.jdbc</groupId>
    <artifactId>ojdbc6</artifactId>
    <version>11.2.0.4</version>
</dependency>
		
		
		
		
		
		
	</dependencies>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>

 

application.properties
#port number set
server.port=3000


#DB set
spring.datasource.driver-class-name=oracle.jdbc.driver.OracleDriver
spring.datasource.url=jdbc:oracle:thin:@localhost:1521:xe
spring.datasource.username=hr
spring.datasource.password=hr

회원가입을 위한 MEMBER Tabel SQL
DROP TABLE MEMBER2

CREATE TABLE MEMBER2(
    ID VARCHAR(50) PRIMARY KEY,
    PWD VARCHAR(60) NOT NULL,
    NAME VARCHAR(50) NOT NULL,
    EMAIL VARCHAR(150) UNIQUE,
    AUTH NUMBER(1)
);

INSERT INTO MEMBER2(ID,PWD,NAME,EMAIL,AUTH)
VALUES('aaa','111','김지매','aaa@naver,com',3);

INSERT INTO MEMBER2(ID,PWD,NAME,EMAIL,AUTH)
VALUES('bbb','222','하지메','hhh@naver,com',3);


INSERT INTO MEMBER2(ID,PWD,NAME,EMAIL,AUTH)
VALUES('ccc','333','아지매','ajm@naver,com',3);

commit;
Member.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="mul.camp.a.dao.MemberDao">
  
  <select id="getId" parameterType="mul.camp.a.dto.MemberDto" resultType="java.lang.Integer">
  SELECT NVL(COUNT(*),0)
  FROM MEMBER2
  WHERE id=#{id}
  </select>
  
  
  <insert id="addmember" parameterType="mul.camp.a.dto.MemberDto">
  INSERT INTO MEMBER2(ID, PWD, NAME, EMAIL, AUTH)
	VALUES(#{id}, #{pwd}, #{name}, #{email}, 3)
  </insert>
  
  <select id="login" parameterType="mul.camp.a.dto.MemberDto"
  resultType="mul.camp.a.dto.MemberDto">
  SELECT ID,NAME,EMAIL,AUTH
  FROM MEMBER2
  WHERE ID=#{id} AND PWD=#{pwd}
  </select>

  
  </mapper>

게시판 생성을 위한 BBS Table SQL
Drop table BBS;

Drop SEQUENCE SEQ_BBS;

CREATE TABLE BBS(
    SEQ NUMBER(8) PRIMARY KEY,
    ID VARCHAR2(50) NOT NULL,    
    REF NUMBER(8) NOT NULL,
    STEP NUMBER(8) NOT NULL,
    DEPTH NUMBER(8) NOT NULL,    
    TITLE VARCHAR2(200) NOT NULL,
    CONTENT VARCHAR2(4000) NOT NULL,
    WDATE DATE NOT NULL,    
    DEL NUMBER(1) NOT NULL,
    READCOUNT NUMBER(8) NOT NULL
);

CREATE SEQUENCE SEQ_BBS
START WITH 1 INCREMENT BY 1;

ALTER TABLE BBS
ADD CONSTRAINT FK_BBS_ID FOREIGN KEY(ID)
REFERENCES MEMBER(ID);

--REF =SELECT NVL(MAX(REF)+1,0)FROM BBS)
INSERT INTO BBS(SEQ,ID,REF,STEP,DEPTH,TITLE,CONTENT,WDATE,DEL,READCOUNT)
VALUES(SEQ_BBS.NEXTVAL,'aaa',(SELECT NVL(MAX(REF)+1,0)FROM BBS),0,0,
    '첫번째 글','내용',SYSDATE,0,0)

commit;
Bbs.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="mul.camp.a.dao.BbsDao">
  
  <select id="getBbsList" resultType="mul.camp.a.dto.BbsDto">
  		SELECT SEQ, ID, REF, STEP, DEPTH, TITLE, CONTENT, WDATE, DEL, READCOUNT
  		FROM BBS
  		ORDER BY REF DESC, STEP ASC
  		
  </select>
  
<insert id="writeBbs" parameterType="mul.camp.a.dto.BbsDto">
	INSERT INTO BBS(SEQ, ID, 
				REF, STEP, DEPTH, 
				TITLE, CONTENT, WDATE, DEL, READCOUNT)
	VALUES(		SEQ_BBS.NEXTVAL, #{id}, 
				(SELECT NVL(MAX(REF)+1, 0) FROM BBS), 0, 0,
				#{title}, #{content}, SYSDATE, 0, 0)
</insert>

<!-- 글 상세페이지 보기 -->
  <select id="getBbs" parameterType="java.lang.Integer" resultType="mul.camp.a.dto.BbsDto">
  		SELECT SEQ, ID, REF, STEP, DEPTH, TITLE, CONTENT, WDATE, DEL, READCOUNT
  		FROM BBS
  		WHERE SEQ=#{seq}
  </select>

<!-- 조회수 업데이트 -->  
<update id="readcount" parameterType="java.lang.Integer">
	UPDATE BBS
	SET READCOUNT=READCOUNT+1
	WHERE SEQ=#{seq}
</update>

<!-- 검색  세가지 조건이 틀려도 에러가 안나오도록 where 1=1-->
<select id="getBbsListSearch" parameterType="mul.camp.a.dto.BbsParam" resultType="mul.camp.a.dto.BbsDto">
	SELECT SEQ, ID, REF, STEP, DEPTH, TITLE, CONTENT, WDATE, DEL, READCOUNT
  	FROM BBS
  	WHERE 1=1 
  		<if test="choice !=null and choice !='' and search !=null and search !=''">
  			<if test="choice=='title'">
  				AND TITLE LIKE '%'||#{search}||'%'
  			</if>
  			<if test="choice=='content'">
  				AND CONTENT LIKE '%'||#{search}||'%'
  			</if>
  			<if test="choice=='writer'">
  				AND ID=#{search}
  			</if>			
  		</if>
  	ORDER BY REF DESC, STEP ASC 	
  </select>
  

<!--ROW_NUMBER()OVER(ORDER BY REF DESC, STEP ASC)란 뜻은 
REF를 내림차순 STEP을 오름차순으로 정렬 한다는 말 그 뒤에 ROW_NUMBER()을 통해서 순번을 차례로 매긴다.
검색해서 나온 결과에 차례로 순번 매긴다고 생각하면 된다.  -->  
<select id="getBbsListSearchPage" parameterType="mul.camp.a.dto.BbsParam" 
									resultType="mul.camp.a.dto.BbsDto">
	SELECT	SEQ, ID, REF, STEP, DEPTH, TITLE, CONTENT, WDATE, DEL, READCOUNT
	FROM							
		(SELECT ROW_NUMBER()OVER(ORDER BY REF DESC, STEP ASC) AS RNUM,
			SEQ, ID, REF, STEP, DEPTH, TITLE, CONTENT, WDATE, DEL, READCOUNT
	  	FROM BBS
	  	WHERE 1=1 
	  		<if test="choice !=null and choice !='' and search !=null and search !=''">
	  			<if test="choice=='title'">
	  				AND TITLE LIKE '%'||#{search}||'%'
	  			</if>
	  			<if test="choice=='content'">
	  				AND CONTENT LIKE '%'||#{search}||'%'
	  			</if>
	  			<if test="choice=='writer'">
	  				AND ID=#{search}
	  			</if>			
	  		</if>
	  	ORDER BY REF DESC, STEP ASC)
	  WHERE RNUM BETWEEN ${start} AND ${end}	 	
  </select>
    
  
  
<!-- 글의 총수 -->
<select id="getBbsCount" parameterType="mul.camp.a.dto.BbsParam" resultType="java.lang.Integer">
	SELECT NVL(COUNT(*), 0) AS CNT
	FROM BBS
	WHERE 1=1
		<if test="choice != null and choice != '' and search != null and search != '' ">
			<if test="choice == 'title'">
				 AND TITLE LIKE '%'||#{search}||'%'
			</if>
			<if test="choice == 'content'">
				 AND CONTENT LIKE '%'||#{search}||'%'
			</if>
			<if test="choice == 'writer'">
				 AND ID=#{search}
			</if>
		</if> 
</select>

 
<!-- 답변시 step 변경--> 
	<update id="replyBbsUpdate" parameterType="mul.camp.a.dto.BbsDto">
	UPDATE BBS
	SET STEP = STEP + 1
	WHERE REF = (SELECT REF FROM BBS WHERE SEQ=#{seq})
		AND STEP > (SELECT STEP FROM BBS WHERE SEQ=#{seq})
	</update>
	
<!-- 답변 -->
<insert id="replyBbsInsert" parameterType="mul.camp.a.dto.BbsDto">
	INSERT INTO BBS(SEQ, ID, REF, STEP, DEPTH, 
					TITLE, CONTENT, WDATE, DEL, READCOUNT)
	VALUES(SEQ_BBS.NEXTVAL, #{id},
			(SELECT REF FROM BBS WHERE SEQ=#{seq}),		<!-- ref --> 
			(SELECT STEP FROM BBS WHERE SEQ=#{seq}) + 1, <!-- step -->
			(SELECT DEPTH FROM BBS WHERE SEQ=#{seq}) + 1, <!-- depth -->
			#{title}, #{content}, SYSDATE,
			0, 0)	
</insert>

<!-- 글 수정 -->
<update id="updateBbs" parameterType="mul.camp.a.dto.BbsDto">
	UPDATE BBS
	SET TITLE=#{title}, CONTENT=#{content}
	WHERE SEQ=#{seq}
</update>

<!-- 글 삭제 -->
<update id="deleteBbs" parameterType="java.lang.Integer">
	UPDATE BBS
	SET DEL=1
	WHERE SEQ=#{seq}
</update>
	
	



  
  </mapper>​

 

댓글 작성을 위한 COMMENT SQL
CREATE TABLE BBSCOMMENT(
	SEQ NUMBER(8),
	ID VARCHAR2(50),
	WDATE DATE,
	CONTENT VARCHAR2(4000)
);

ALTER TABLE BBSCOMMENT
ADD CONSTRAINT FK_COMMENT_ID FOREIGN KEY(ID)
REFERENCES MEMBER2(ID);

commit;
<?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="mul.camp.a.dao.CommentDao">

<select id="getCommentList" parameterType="java.lang.Integer" resultType="mul.camp.a.dto.CommentDto">
	SELECT SEQ, ID, WDATE, CONTENT
	FROM BBSCOMMENT
	WHERE SEQ=#{seq}
	ORDER BY WDATE DESC
</select>

<insert id="writeComment" parameterType="mul.camp.a.dto.CommentDto">
	INSERT INTO BBSCOMMENT(SEQ, ID, WDATE, CONTENT)
	VALUES(#{seq}, #{id}, SYSDATE, #{content})
</insert>

</mapper>

package mul.camp.a.dto;

public class MemberDto {

	private String id;
	private String pwd;
	private String name;
	private String email;
	private int auth;
	
	public MemberDto() {
		
	}
	
	public MemberDto(String id, String pwd, String name, String email, int auth) {
		super();
		this.id = id;
		this.pwd = pwd;
		this.name = name;
		this.email = email;
		this.auth = auth;
	}

	public String getId() {
		return id;
	}

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

	public String getPwd() {
		return pwd;
	}

	public void setPwd(String pwd) {
		this.pwd = pwd;
	}

	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 int getAuth() {
		return auth;
	}

	public void setAuth(int auth) {
		this.auth = auth;
	}

	@Override
	public String toString() {
		return "MemberDto [id=" + id + ", pwd=" + pwd + ", name=" + name + ", email=" + email + ", auth=" + auth + "]";
	}


	
	
}​

 

 

MemberDao.java(인터페이스)
package mul.camp.a.dao;

import java.util.List;

import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;

import mul.camp.a.dto.MemberDto;

@Mapper
@Repository
public interface MemberDao {
	
	public int getId(MemberDto dto);
	
	public int addmember(MemberDto dto);
	
	public MemberDto login(MemberDto dto);
	

	
}

 

MemberService.java
package mul.camp.a.service;

import java.util.List;

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

import mul.camp.a.dao.MemberDao;
import mul.camp.a.dto.MemberDto;

@Service
@Transactional
public class MemberService {
	
	@Autowired
	MemberDao dao;
		
	public boolean getId(MemberDto dto) {
		int n = dao.getId(dto);
		
		return n>0?true:false;
	}
	
	
	public boolean addmember(MemberDto dto) {
		int n = dao.addmember(dto);
		
		return n>0?true:false;
	}
	
	public MemberDto login(MemberDto dto) {
		
		return dao.login(dto);
	}
}

 

MemberController.java
package mul.camp.a.controller;

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import mul.camp.a.dto.MemberDto;
import mul.camp.a.service.MemberService;

@RestController
public class MemberController {

	@Autowired
	MemberService service;
	

	@RequestMapping(value="/getId", method= {RequestMethod.GET, RequestMethod.POST})
		public String getId(MemberDto dto) {
		System.out.println("MemberController getID");
		
		boolean b = service.getId(dto);
		if(b) {
			return "NO"; //1이상이란 말, 이미 아이디가 존재한다는 말이라서 사용이 안된다
		}
		return "OK";
	}
	
	@RequestMapping(value="/addmember", method= {RequestMethod.GET, RequestMethod.POST})
	public String addmember(MemberDto dto) {
		System.out.println("MemberController addmember");		
		boolean b = service.addmember(dto);
		
	if(b) {
		return "YES";
	}
	return "NO";
	}
	
	@RequestMapping(value="/login", method= {RequestMethod.GET, RequestMethod.POST})
	public MemberDto login(MemberDto dto, HttpServletRequest req) {
		System.out.println("MemberController login");	
		
	
		MemberDto mem = service.login(dto);
		
		//이렇게 사용할수 있다는 말
		req.getSession().setAttribute("login", mem);
		
		
		return mem;
	}

}

 


 

 

BbsDto.java
package mul.camp.a.dto;



public class BbsDto {
	private int seq;
	private String id;
	
	//답글용 
	private int ref;
	private int step;
	
	private int depth;
	
	private String title;
	private String content;
	private String wdate;
	
	private int del;
	private int readcount; //조회수
	
	public BbsDto() {}
	
	public BbsDto(int seq, String id, int ref, int step, int depth, String title, String content, String wdate, int del,
			int readcount) {
		super();
		this.seq = seq;
		this.id = id;
		this.ref = ref;
		this.step = step;
		this.depth = depth;
		this.title = title;
		this.content = content;
		this.wdate = wdate;
		this.del = del;
		this.readcount = readcount;
	}
	
	
	
	public BbsDto(String id, String title, String content) {
		super();
		this.id = id;
		this.title = title;
		this.content = content;
	}

	public int getSeq() {
		return seq;
	}
	public void setSeq(int seq) {
		this.seq = seq;
	}
	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}
	public int getRef() {
		return ref;
	}
	public void setRef(int ref) {
		this.ref = ref;
	}
	public int getStep() {
		return step;
	}
	public void setStep(int step) {
		this.step = step;
	}
	public int getDepth() {
		return depth;
	}
	public void setDepth(int depth) {
		this.depth = depth;
	}
	public String getTitle() {
		return title;
	}
	public void setTitle(String title) {
		this.title = title;
	}
	public String getContent() {
		return content;
	}
	public void setContent(String content) {
		this.content = content;
	}
	public String getWdate() {
		return wdate;
	}
	public void setWdate(String wdate) {
		this.wdate = wdate;
	}
	public int getDel() {
		return del;
	}
	public void setDel(int del) {
		this.del = del;
	}
	public int getReadcount() {
		return readcount;
	}
	public void setReadcount(int readcount) {
		this.readcount = readcount;
	}

	
	
	@Override
	public String toString() {
		return "BbsDto [seq=" + seq + ", id=" + id + ", ref=" + ref + ", step=" + step + ", depth=" + depth + ", title="
				+ title + ", content=" + content + ", wdate=" + wdate + ", del=" + del + ", readcount=" + readcount
				+ "]";
	}
	
	

	

}
BbsParam.java
package mul.camp.a.dto;

public class BbsParam {

	private String choice; //제목, 내용,작성자
	private String search; //검색어
	
	private int page; //현재 페이지

	private int start; //페이지 글의 범위
	private int end; 
	
	
	public BbsParam() {}


	public BbsParam(String choice, String search, int page, int start, int end) {
		super();
		this.choice = choice;
		this.search = search;
		this.page = page;
		this.start = start;
		this.end = end;
	}


	public String getChoice() {
		return choice;
	}


	public void setChoice(String choice) {
		this.choice = choice;
	}


	public String getSearch() {
		return search;
	}


	public void setSearch(String search) {
		this.search = search;
	}


	public int getPage() {
		return page;
	}


	public void setPage(int page) {
		this.page = page;
	}


	public int getStart() {
		return start;
	}


	public void setStart(int start) {
		this.start = start;
	}


	public int getEnd() {
		return end;
	}


	public void setEnd(int end) {
		this.end = end;
	}
	
	@Override
	public String toString() {
		return "BbsParam [choice=" + choice + ", search=" + search + ", page=" + page + ", start=" + start + ", end="
				+ end + "]";
	}	

	
	
}
BbsDao.java(인터페이스)
package mul.camp.a.dao;

import java.util.List;

import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;

import mul.camp.a.dto.BbsDto;
import mul.camp.a.dto.BbsParam;

@Mapper
@Repository
public interface BbsDao {

	public List<BbsDto> getBbsList();
	
	public int writeBbs(BbsDto dto);
	
	public BbsDto getBbs(int seq);
	public void readcount(int seq);
	
	int replyBbsUpdate(BbsDto dto);
	int replyBbsInsert(BbsDto dto);
	
	public int updateBbs(BbsDto dto);
	
	public int deleteBbs(int seq);
	
	public List<BbsDto> getBbsListSearch(BbsParam param);
	
	public List<BbsDto> getBbsListSearchPage(BbsParam param);
	
	public int getBbsCount(BbsParam param);
	
	
}

 

BbsService.java
package mul.camp.a.service;

import java.util.List;

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

import mul.camp.a.dao.BbsDao;
import mul.camp.a.dto.BbsDto;
import mul.camp.a.dto.BbsParam;

@Service
@Transactional
public class BbsService {

	@Autowired
	BbsDao dao;
	
	public List<BbsDto> getBbsList(){
		return dao.getBbsList();
	}
	
	public boolean writeBbs(BbsDto dto) {
		int n = dao.writeBbs(dto);
		return n>0?true:false;
	}
	
	public BbsDto getBbs(int seq) {		
		return dao.getBbs(seq);
	}
	
	public void readcount(int seq) {
		dao.readcount(seq);
	}
	
	
	public boolean reply(BbsDto dto) {
		dao.replyBbsUpdate(dto);
		int n2 = dao.replyBbsInsert(dto); //1이 나와야한다
		System.out.println("n2:" + n2);
		if(n2 == 0) {
			return false;
		}
		return true;
	}
	
	
	public List<BbsDto> getBbsListSearch(BbsParam param){
		return dao.getBbsListSearch(param);
	}
	
	public List<BbsDto> getBbsListSearchPage(BbsParam param){
		return dao.getBbsListSearchPage(param);
	}
	
	public int getBbsCount(BbsParam param) {
		return dao.getBbsCount(param);
	}
	
	public boolean updateBbs(BbsDto dto) {
		int n = dao.updateBbs(dto);
		if(n > 0) {
			return true;
		}
		return false;
	}
	
	public boolean deleteBbs(int seq) {
		int n = dao.deleteBbs(seq);
		if(n == 0) return false;
		
		return true;
	}
	

}

 

BbsController.java
package mul.camp.a.controller;

import java.sql.Date;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import mul.camp.a.dto.BbsDto;
import mul.camp.a.dto.BbsParam;
import mul.camp.a.service.BbsService;

@RestController
public class BbsController {

	@Autowired
	BbsService service;
	
	@RequestMapping(value= "/getBbsList", method= {RequestMethod.GET, RequestMethod.POST})
	public List<BbsDto> getBbsList(){
		System.out.println("BbsController getBbsList");
		
		List<BbsDto> list = service.getBbsList();
		return list;
	}
	
	@RequestMapping(value = "/bbswrite", method = {RequestMethod.GET, RequestMethod.POST} )
	public String bbswrite(BbsDto dto) {
		System.out.println("BbsController bbswrite");
		
		boolean b = service.writeBbs(dto);
		if(b) {
			return "YES";
		}
		return "NO";
	}
	
	@RequestMapping(value = "/bbsdetail", method = {RequestMethod.GET, RequestMethod.POST} )
	public BbsDto bbsdetail(int seq) {
		System.out.println("BbsController bbsdetail");
		
		service.readcount(seq);	
		return service.getBbs(seq);		
		
	}
	
	
	@RequestMapping(value= "/getBbsListSearch", method= {RequestMethod.GET, RequestMethod.POST})
	public List<BbsDto> getBbsListSearch(BbsParam param){
		System.out.println("BbsController getBbsListSearch");
		
		return service.getBbsListSearch(param);
	}
	
	@RequestMapping(value= "/getBbsListSearchPage", method= {RequestMethod.GET, RequestMethod.POST})
	public List<BbsDto> getBbsListSearchPage(BbsParam param){
		System.out.println("BbsController getBbsListSearchPage");
		
		//페이지 설정
		int sn = param.getPage(); 	//현재페이지 0 1 2 3 ~
		int start = sn*10+1;		//		  1     11
		int end = (sn+1)*10;		//		 10     20
		
		param.setStart(start);
		param.setEnd(end);
		
		return service.getBbsListSearchPage(param);


	}
	
	@RequestMapping(value= "/getBbsCount", method= {RequestMethod.GET, RequestMethod.POST})
	public int getBbsCount(BbsParam param) {
		System.out.println("BbsController getBbsCount");
		return service.getBbsCount(param);
	}
	
	@RequestMapping(value = "/answer", method = {RequestMethod.GET, RequestMethod.POST} )
	public String answer(BbsDto dto) {
		System.out.println("BbsController answer ");
		System.out.println("dto:" + dto.toString());
		
		boolean b = service.reply(dto);
		
		if(b) { 
			return "OK"; 
		}		 
		return "NO";
	}
	
	@RequestMapping(value = "/bbsupdate", method = {RequestMethod.GET, RequestMethod.POST} )
	public String bbsupdate(BbsDto dto) {
		System.out.println("BbsController bbsupdate ");
		
		boolean b = service.updateBbs(dto);
		if(b) {
			return "OK";
		}
		return "NO";
	}
	
	@RequestMapping(value = "/bbsdelete", method = {RequestMethod.GET, RequestMethod.POST} )
	public String bbsdelete(int seq) {
		System.out.println("BbsController bbsdelete ");
		
		boolean b = service.deleteBbs(seq);
		if(b) {
			return "OK";
		}
		return "NO";		
	}
	

	
	
}

 


CommentDto.java
package mul.camp.a.dto;


public class CommentDto {
	private int seq;
	private String id;
	private String wdate;
	private String content;
	
	public CommentDto(){		
	}

	public CommentDto(int seq, String id, String wdate, String content) {
		super();
		this.seq = seq;
		this.id = id;
		this.wdate = wdate;
		this.content = content;
	}

	public int getSeq() {
		return seq;
	}

	public void setSeq(int seq) {
		this.seq = seq;
	}

	public String getId() {
		return id;
	}

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

	public String getWdate() {
		return wdate;
	}

	public void setWdate(String wdate) {
		this.wdate = wdate;
	}

	public String getContent() {
		return content;
	}

	public void setContent(String content) {
		this.content = content;
	}

	@Override
	public String toString() {
		return "CommentDto [seq=" + seq + ", id=" + id + ", wdate=" + wdate + ", content=" + content + "]";
	}	
}

 

CommentDao.java(인터페이스)
package mul.camp.a.dao;

import java.util.List;

import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;

import mul.camp.a.dto.CommentDto;

@Mapper
@Repository
public interface CommentDao {
	
	public List<CommentDto> getCommentList(int seq); 
	
	public int writeComment(CommentDto dto);
}

 

CommentService.java
package mul.camp.a.service;

import java.util.List;

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

import mul.camp.a.dao.CommentDao;
import mul.camp.a.dto.CommentDto;

@Service
@Transactional
public class CommentService {
	
	@Autowired
	CommentDao dao;
	
	public List<CommentDto> getCommentList(int seq) {
		return dao.getCommentList(seq);
	}
	
	public boolean writeComment(CommentDto dto) {
		int n = dao.writeComment(dto);
		if(n > 0) {
			return true;
		}
		return false;
	}
}

 

CommentController.java
package mul.camp.a.service;

import java.util.List;

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

import mul.camp.a.dao.CommentDao;
import mul.camp.a.dto.CommentDto;

@Service
@Transactional
public class CommentService {
	
	@Autowired
	CommentDao dao;
	
	public List<CommentDto> getCommentList(int seq) {
		return dao.getCommentList(seq);
	}
	
	public boolean writeComment(CommentDto dto) {
		int n = dao.writeComment(dto);
		if(n > 0) {
			return true;
		}
		return false;
	}
}




package mul.camp.a.service;

import java.util.List;

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

import mul.camp.a.dao.CommentDao;
import mul.camp.a.dto.CommentDto;

@Service
@Transactional
public class CommentService {
	
	@Autowired
	CommentDao dao;
	
	public List<CommentDto> getCommentList(int seq) {
		return dao.getCommentList(seq);
	}
	
	public boolean writeComment(CommentDto dto) {
		int n = dao.writeComment(dto);
		if(n > 0) {
			return true;
		}
		return false;
	}
}

 

백엔드는 여기서 끝


프론트엔드 시작

 

 

Eclipse를 이용한 프론트 엔드 폴더 및 파일구조

답글에 표시할 화살표 이미지 arrow.png

 

arrow.png
0.02MB

 

 

페이징에 사용할 플러그인 jquery.twbsPagination.min.ja

jquery.twbsPagination.min.js
0.01MB

 

index.html (제일 처음 실행하는 페이지)
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>

<script type="text/javascript">
location.href = "login.html";
</script>

</body>
</html>

 

login.html (로그인 화면)
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>

<style type="text/css">
.center{
	margin: auto;
	width: 60%;
	border: 3px solid;
	padding: 10px;	
}
.divider:after,
.divider:before {
  content: "";
  flex: 1;
  height: 1px;
  background: #eee;
}
.h-custom {
  height: calc(100% - 73px);
}
@media (max-width: 450px) {
  .h-custom {
    height: 100%;
  }
}
</style>

<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.16.0/umd/popper.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>

</head>
<body>

<div id="app">

<section class="vh-100">
  <div class="container-fluid h-custom">
    <div class="row d-flex justify-content-center align-items-center h-100">
      <div class="col-md-9 col-lg-6 col-xl-5">
        <img src="https://www.multicampus.com/kr/images/main/2021/tab-image3.jpg" class="img-fluid"
          alt="Sample image">
      </div>
      <div class="col-md-8 col-lg-6 col-xl-4 offset-xl-1">
        <form action="loginAf.do" method="post">
          <div class="d-flex flex-row align-items-center justify-content-center justify-content-lg-start">
            <p class="lead fw-normal mb-0 me-3">Sign in with</p>            
          </div>

          <div class="divider d-flex align-items-center my-4">
            <p class="text-center fw-bold mx-3 mb-0">Or</p>
          </div>

          <!-- id input -->
          <div class="form-outline mb-4">
            <input type="text" id="id" name="id" class="form-control form-control-lg"
              placeholder="Enter a valid id" />
            <label class="form-label" for="form3Example3">Id</label>
          </div>

          <!-- Password input -->
          <div class="form-outline mb-3">
            <input type="password" id="pwd" name="pwd" class="form-control form-control-lg"
              placeholder="Enter password" />
            <label class="form-label" for="form3Example4">Password</label>
          </div>

          <div class="d-flex justify-content-between align-items-center">
            <!-- Checkbox -->
            <div class="form-check mb-0">
              <input class="form-check-input me-2" type="checkbox" value="" id="chk_save_id" />
              <label class="form-check-label" for="form2Example3">
                Remember me
              </label>
            </div>
            <a href="#!" class="text-body">Forgot password?</a>
          </div>

          <div class="text-center text-lg-start mt-4 pt-2">
            <button type="button" id="login" class="btn btn-primary btn-lg"
              style="padding-left: 2.5rem; padding-right: 2.5rem;">Login</button>
            <p class="small fw-bold mt-2 pt-1 mb-0">Don't have an account? <a href="account.html" 
                class="link-danger">Register</a></p>
          </div>

        </form>
      </div>
    </div>
  </div>
  <div class="d-flex flex-column flex-md-row text-center text-md-start justify-content-between py-4 px-4 px-xl-5 bg-primary">
    <!-- Copyright -->
    <div class="text-white mb-3 mb-md-0">
      Copyright © 2022. MultiCampus.
    </div>
    <!-- Copyright -->

    <!-- Right -->
    <div>
      <a href="#!" class="text-white me-4">
        <i class="fab fa-facebook-f"></i>
      </a>
      <a href="#!" class="text-white me-4">
        <i class="fab fa-twitter"></i>
      </a>
      <a href="#!" class="text-white me-4">
        <i class="fab fa-google"></i>
      </a>
      <a href="#!" class="text-white">
        <i class="fab fa-linkedin-in"></i>
      </a>
    </div>
    <!-- Right -->
  </div>
</section>

</div>

<script type="text/javascript">
$(document).ready(function () {

	$("#login").click(function () {
		// alert($("#id").val() + $("#pwd").val());
		$.ajax({
			url:"http://localhost:3000/login",
			type:"post",
			data:{ id:$("#id").val(), pwd:$("#pwd").val() },
			success:function(json){
			//	alert('success');
			//	alert(JSON.stringify(json));
				if(json == ""){
					alert("id나 비밀번호를 확인하세요");
					$("#id").val("");
					$("#pwd").val("");
				}else{
					sessionStorage.setItem("login", JSON.stringify(json));
					alert(json.name + "님 환영합니다");	
					
					location.href = "bbslist.html";
				}			
			},
			error:function(){
				alert('error');
			}			
		});
		
	});	
	
});

</script>

</body>
</html>

 

account.html(회원가입)
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>

<link href="//maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" rel="stylesheet" id="bootstrap-css">
<script src="//maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>

<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.0.8/css/all.css">
</head>
<body>

<div class="container">

<article class="card-body mx-auto" style="max-width: 400px;">
	<h4 class="card-title mt-3 text-center">회원가입</h4>	
	<form id="frm">
	
	<div class="form-group input-group">
		<div class="input-group-prepend">
		    <span class="input-group-text"> <i class="fa fa-user"></i> </span>
		 </div>
        <input id="userid" name="userid" class="form-control" placeholder="아이디입력" type="text">   
           
    </div> <!-- form-group// -->   
    
    <div class="form-group input-group">
    	<button type="button" id="btn" class="btn btn-primary btn-danger">id check</button>   
    	<p id="idcheck" style="margin-left:10px; padding-top: 10px;">id 확인</p>   	
    </div>    
    
    <div class="form-group input-group">
		<div class="input-group-prepend">
		    <span class="input-group-text"> <i class="fa fa-user"></i> </span>
		 </div>
        <input id="id" name="id" class="form-control" placeholder="id" type="text" readonly="readonly">  
    </div>
    	
	<div class="form-group input-group">
		<div class="input-group-prepend">
		    <span class="input-group-text"> <i class="fa fa-user"></i> </span>
		 </div>
        <input name="name" class="form-control" placeholder="Full name" type="text">
    </div> <!-- form-group// -->
    
    <div class="form-group input-group">
    	<div class="input-group-prepend">
		    <span class="input-group-text"> <i class="fa fa-envelope"></i> </span>
		 </div>
        <input name="email" class="form-control" placeholder="Email address" type="email">
    </div> <!-- form-group// -->
    
    <div class="form-group input-group">
    	<div class="input-group-prepend">
		    <span class="input-group-text"> <i class="fa fa-phone"></i> </span>
		</div>
		<select class="custom-select" style="max-width: 120px;">
		    <option selected="selected">+02</option>
		    <option value="1">+032</option>
		    <option value="2">+041</option>
		    <option value="3">+053</option>
		</select>
    	<input name="" class="form-control" placeholder="Phone number" type="text">
    </div> <!-- form-group// -->
    <div class="form-group input-group">
    	<div class="input-group-prepend">
		    <span class="input-group-text"> <i class="fa fa-building"></i> </span>
		</div>
		<select class="form-control">
			<option selected="selected">직업</option>
			<option>디자이너</option>
			<option>프로그래머</option>
			<option>자영업</option>
		</select>
	</div> <!-- form-group end.// -->
    <div class="form-group input-group">
    	<div class="input-group-prepend">
		    <span class="input-group-text"> <i class="fa fa-lock"></i> </span>
		</div>
        <input id="" class="form-control" name="pwd" placeholder="Create password" type="password">
    </div> <!-- form-group// -->
    
    <div class="form-group input-group">
    	<div class="input-group-prepend">
		    <span class="input-group-text"> <i class="fa fa-lock"></i> </span>
		</div>
        <input class="form-control" placeholder="Repeat password" type="password">
    </div> <!-- form-group// --> 
                                         
    <div class="form-group">
        <button type="button" id="account" class="btn btn-primary btn-block"> Create Account  </button>
    </div> <!-- form-group// -->      
    <p class="text-center">Have an account? <a href="login.html">Log In</a> </p>                                                                 
</form>
</article>

</div> 
<!--container end.//-->

<script type="text/javascript">
$(document).ready(function () {
	
	$("#btn").click(function () {		
		$.ajax({
			url:"http://localhost:3000/getId",
			type:"post",
			data:{ "id":$("#userid").val() },
			success:function( msg ){
				//alert('success');
				//alert(msg);
				if(msg.trim() == 'OK'){
					$("#idcheck").html("이 아이디는 사용할 수 있습니다");
					$("#id").val( $("#userid").val() )
				}else{
					$("#idcheck").html("이 아이디는 사용중입니다");
					$("#userid").val("");
					$("#userid").focus();
				}
			},
			error:function(){
				alert('error');
			}
		});		
	});
	
	$("#account").on("click", function () {		
		alert('account');
		
		let params = $("#frm").serialize()
		
		// let params = { id:$("#id").val(), pwd:$("#pwd").val(), name:$("#name").val(), email:$("#email").val() };
		
		$.ajax({
			url:"http://localhost:3000/addmember",
			type:"post",
			// data:{ id:$("#id").val(), pwd:$("#pwd").val(), name:$("#name").val(), email:$("#email").val() },
			data:params,
			success:function(data){
				//alert("success");
				if(data == "YES"){
					alert('가입성공');
					location.href = "login.html";
				}else{
					alert('가입실패');
				}
			},
			error:function(){
				alert("error");
			}
		});
		
	});
	
});
</script>

</body>
</html>

 

bbslist.html (게시판 목록)
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>bbslist</title>
<script
	src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>

<link rel="stylesheet"
	href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
<script
	src="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>

<style type="text/css">
th{
	text-align: center;
}
</style>

<script type="text/javascript"
	src="./jquery/jquery.twbsPagination.min.js"></script>
</head>
<body>
<br>
<br>
<div id="app" class="container">	
	<table style="margin-left: auto; margin-right: auto; margin-top: 3px; margin-bottom: 3px">
		<tr>
			<td style="padding-left: 5px"><select class="custom-select"
				id="_choice" name="choice">
					<option selected>선택</option>
					<option value="title">제목</option>
					<option value="content">내용</option>
					<option value="writer">작성자</option>
			</select></td>
			<td style="padding-left: 5px" class="align-middle"><input
				type="text" class="form-control" id="_search" name="search"
				placeholder="검색어">
			<td style="padding-left: 5px"><span>
					<button type="button" class="btn btn-primary" id="btnSearch">검색</button>
			</span></td>
		</tr>
	</table>	
	<br>

	<table class="table table-striped table-hover">
		<thead>
			<tr>
				<th>번호</th>
				<th>제목</th>
				<th>작성자</th>
				<th>seq</th>
			</tr>
		</thead>

		<tbody id="tbody">
		</tbody>

	</table>
	<br><br>

	<div class="container">
		<nav aria-label="Page navigation">
			<ul class="pagination" id="pagination"
				style="justify-content: center"></ul>
		</nav>
	</div>
	<br><br>

	<div align="center">
		<!-- <a href="bbswrite.html">글쓰기</a> -->
		<button type="button" id="writeBtn" class="btn btn-primary">글쓰기</button>
	</div>
	<br><br>

</div>

<script type="text/javascript">
$(document).ready(function () {
	let str = sessionStorage.getItem("login");	
	let json = JSON.parse(str);	
	
	getBbslist( 0 );
	getBbsCount();
	
	
	
	$("#btnSearch").click(function () {
		getBbslist( 0 );
		getBbsCount();		
	});
	 
	 $("#writeBtn").click(function () {
		location.href = "bbswrite.html";
	});
	
})

function getBbslist( page ) {
	let choice = $("#_choice").val();
	let search = $("#_search").val();
	
	$("#tbody").html(""); // 테이블 초기화
	$.ajax({
		url:"http://localhost:3000/getBbsListSearchPage",
		type:"get",
		data:{ "choice":choice, "search":search, "page":page },
		success:function(list){
			
			$.each(list, function (i, item) {
				
				let str = "<tr>"
							+ "<th>" + (i + 1) + "</th>";
				
				if(item.del == 0){
					str +=	  "<td>" + getArrow(item.depth) + "&nbsp;&nbsp;<a href='bbsdetail.html?seq=" + item.seq + "'>" + item.title + "</a></td>"
				}
				else{
					str +=	  "<td align='center'><font color='#ff0000'>- 이 글은 작성자에 의해서 삭제되었습니다 -</font></td>"
				}
				
					str +=	  "<td>" + item.id + "</td>"
							+ "<td>" + item.seq + "</td>"
						+ "</tr>";	
						
				$("#tbody").append(str);
			});
		},
		error:function(){
			alert('error');	
		}			
	});
}

// 글의 총수를 취득
function getBbsCount() {
	let choice = $("#_choice").val();
	let search = $("#_search").val();
	
	$.ajax({
		url:"http://localhost:3000/getBbsCount",
		type:"get",
		data:{ "choice":choice, "search":search, "page":0 },
		success:function(count){
			//alert(count);
			loadPage(count);
		},
		error:function(){
			alert('getBbsCount error');
		}		
	});	
}

function loadPage( totalCount ) { // 글의 총수		 
	let pageSize = 10;		
	
	let _totalPages = totalCount / 10 // 10 10 3
	if(totalCount % 10 > 0){
		_totalPages++;
	}
	
	$('#pagination').twbsPagination('destroy');	// 페이지 갱신
	
	$('#pagination').twbsPagination({		
	    totalPages: _totalPages,
	    visiblePages: 10,
	    first:'<span sris-hidden="true">«</span>',
	    last:'<span sris-hidden="true">»</span>',
	    prev:"이전",
	    next:"다음",
	    initiateStartPageClick:false,	// onPageClick 자동호출 방지
	    onPageClick: function (event, page) {
	        // alert(page);
	        getBbslist( page - 1 );
	    }
	})
}

function getArrow( depth ) {
	let rs = "<img src='./image/arrow.png' width='20px' height='20'/>";
	let nbsp = "&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;";
	
	let ts = "&nbsp;&nbsp;";
	for(i = 0;i < depth; i++){		// __ >>
		ts += nbsp;
	}
	return depth==0?"":ts + rs;
}


</script>

</body>
</html>

 

 

bbswrite.html (글작성)
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.16.0/umd/popper.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
</head>
<body>

<h1>글추가</h1>

<div align="center">

<form id="frm">

<div align="center">
	<div style="width: 1000px">

		<table class="table table-bordered">
		<col width="200"><col width="400">
		
		<tr>
			<th class="table-primary">아이디</th>
			<td>
				<input type="text" id="id" name="id" size="50px" readonly="readonly">
			</td>
		</tr>
		
		<tr>
			<th class="table-primary">제목</th>
			<td>
				<input type="text" class="form-control" name="title" size="50px">
			</td>
		</tr>
		
		<tr>
			<th class="table-primary">내용</th>
			<td>
				<textarea class="form-control" rows="10" name="content"></textarea>
			</td>
		</tr>
		<tr>
			<td colspan="2" align="center">
				<button type="button" id="btn" class="btn btn-secondary">작성완료</button>
			</td>	
		</tr>
		</table>
		
	</div>
</div>

</form>
</div>

<script type="text/javascript">
let login = sessionStorage.getItem("login");
let id = JSON.parse(login).id;
// alert(id);
$("#id").val(id);

$("#btn").click(function () {
	
	$.ajax({
		url:"http://localhost:3000/bbswrite",
		type:"get",
		data:$("#frm").serialize(),
		success:function(msg){
			if(msg == "YES"){
				alert('추가되었습니다');
				location.href = "bbslist.html";	
			}else{
				alert('추가되지 않았습니다');
			}			
		},
		error:function(){
			alert('error');
		}
	})
	
});

</script>


</body>
</html>

 

 

 

bbsdetail.html (글 클릭했을때 상세페이지, 댓글 기능 추가)
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>bbsdetail</title>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>

<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>

<style type="text/css">
th{
	background-color: #007bff;
	color: white;
}
pre { /* 자동줄바꿈 설정 */
  	white-space: pre-wrap;
    word-break: break-all;
    overflow: auto;
}
</style>


</head>
<body>

<h2>내용보기</h2>

<div id="app" class="container">

<table class="table table-striped">
<col width="150"><col width="500">
<tr>
	<th>작성자</th><td id="id"></td>
</tr>

<tr>
	<th>작성일</th><td id="wdate"></td>
</tr>

<tr>
	<th>조회수</th><td id="readcount"></td>
</tr>

<tr>
	<!-- <th>제목</th> -->
	<td colspan="2" id="title" style="font-size: 22px; font-weight:bold;"></td>
</tr>

<tr>
	<!-- <th>내용</th> -->
	<td colspan="2" style="background-color: white;">
		<pre id="content" style="font-size: 20px; 
			font-family: 고딕,arial;background-color: white;"></pre>
	</td>	
</tr>

</table>
<br><br>


<button type="button" id="bbsanswer" class="btn btn-primary">답글작성</button>

<button type="button" id="bbsupdate" class="btn btn-primary">수정</button>
<button type="button" id="bbsdelete" class="btn btn-primary">삭제</button>

<br><br>

<table>
<col width="1500px"><col width="150">
<tr>
<td>comment</td><td style="padding-left: 30px">올리기</td>
</tr>
<tr>
	<td>
		<textarea rows="3" class="form-control" id="commentContent"></textarea>
	</td>
	<td style="padding-left: 30px">		
		<button type="button" class="btn btn-primary btn-block p-4" id="commentBtn">완료</button>
	</td>
</tr>
</table>
<br><br>


<table class="table">
	<col width="500"><col width="500">
	<tbody id="tbody">
		<!-- <tr>
			<td>작성자</td>
			<td>날짜</td>
		</tr>
		<tr>
			<td colspan="2">내용</td>
		</tr> -->
	</tbody>
</table>


</div>

<br><br><br><br><br><br>

<script type="text/javascript">
let str = sessionStorage.getItem("login");	
let json = JSON.parse(str);

const url = new URL(location.href);
const urlParams = url.searchParams;
let seq = urlParams.get("seq");

//alert("seq: " + seq);
commentList();

$.ajax({
	url:"http://localhost:3000/bbsdetail",
	type:"get",
	data:{ "seq":seq },
	success:function(bbs){
		//alert('success');
		//alert(JSON.stringify(bbs));
		
		$("#id").text(bbs.id);
		$("#title").text(bbs.title);
		$("#wdate").text(bbs.wdate);
		$("#readcount").text(bbs.readcount);
		$("#content").text(bbs.content);
		
		let login = JSON.parse(sessionStorage.getItem("login"));
		if(bbs.id != login.id){
			$("#bbsupdate").hide();
			$("#bbsdelete").hide();
		}
		
	},
	error:function(){
		alert('error');
	}
	
});

$("#bbsanswer").click(function () {	
	location.href = "bbsanswer.html?seq=" + seq;
});

$("#bbsupdate").click(function () {	
	location.href = "bbsupdate.html?seq=" + seq;
});

$("#bbsdelete").click(function () {	
	$.ajax({
		url:"http://localhost:3000/bbsdelete",
		type:"get",
		data:{ "seq":seq },
		success:function(msg){
			if(msg == "OK"){
				alert("삭제되었습니다");
				location.href = "bbslist.html";
			}else{
				alert("삭제되지 않았습니다");
			}
		},
		error:function(){
			alert('error');
		}
	})
});

$("#commentBtn").click(function () {
	commentWrite();	
});

function commentWrite() {
	
	if($("#commentContent").val().trim() == ""){
		alert("코멘트를 작성해 주세요");
		return;
	}
	
	$.ajax({
		url:"http://localhost:3000/commentWrite",
		type:"get",
		data:{ "seq":seq, "id":json.id, "content":$("#commentContent").val() },
		success:function(msg){			
			commentList();
			$("#commentContent").val("");
		},
		error:function(){
			alert('error');
		}
	})	
}

function commentList() {
	$.ajax({
		url:"http://localhost:3000/getCommentList",
		type:"get",
		data:{ "seq":seq },
		success:function(list){
			
			$("#tbody").html("");
			
			$.each(list, function (i, item) {
				let str = "<tr class='table-info'>" +
				 				"<td>작성자: " + item.id +"</td>" +
								"<td >작성일: " + item.wdate + "</td>" + 
						  "</tr>" +
						  "<tr>" +
								"<td colspan='2'>" + item.content + "</td>" +
						  "</tr>";						  
				$("#tbody").append(str);							
			});
		},
		error:function(){
			alert('error');
		}
	})	
}




</script>

</body>
</html>

 

bbsanswer.html (답글 작성 페이지 )
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>bbsdetail</title>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>

<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>

<style type="text/css">
th{
	background-color: #007bff;
	color: white;
}
pre { /* 자동줄바꿈 설정 */
  	white-space: pre-wrap;
    word-break: break-all;
    overflow: auto;
}
</style>


</head>
<body>

<h2>내용보기</h2>

<div id="app" class="container">

<table class="table table-striped">
<col width="150"><col width="500">
<tr>
	<th>작성자</th><td id="id"></td>
</tr>

<tr>
	<th>작성일</th><td id="wdate"></td>
</tr>

<tr>
	<th>조회수</th><td id="readcount"></td>
</tr>

<tr>
	<!-- <th>제목</th> -->
	<td colspan="2" id="title" style="font-size: 22px; font-weight:bold;"></td>
</tr>

<tr>
	<!-- <th>내용</th> -->
	<td colspan="2" style="background-color: white;">
		<!-- <textarea rows="15" class="form-control" id="content" style="font-size: 20px; 
			font-family: 고딕,arial;background-color: white;" readonly></textarea> -->
		<pre id="content" style="font-size: 20px; 
			font-family: 고딕,arial;background-color: white;"></pre>
	</td>	
</tr>

</table>
<br><br>


<button type="button" id="bbsanswer" class="btn btn-primary">답글작성</button>

<button type="button" id="bbsupdate" class="btn btn-primary">수정</button>
<button type="button" id="bbsdelete" class="btn btn-primary">삭제</button>

<br><br>

<table>
<col width="1500px"><col width="150">
<tr>
<td>comment</td><td style="padding-left: 30px">올리기</td>
</tr>
<tr>
	<td>
		<textarea rows="3" class="form-control" id="commentContent"></textarea>
	</td>
	<td style="padding-left: 30px">		
		<button type="button" class="btn btn-primary btn-block p-4" id="commentBtn">완료</button>
	</td>
</tr>
</table>
<br><br>


<table class="table">
	<col width="500"><col width="500">
	<tbody id="tbody">
		<!-- <tr>
			<td>작성자</td>
			<td>날짜</td>
		</tr>
		<tr>
			<td colspan="2">내용</td>
		</tr> -->
	</tbody>
</table>


</div>

<br><br><br><br><br><br>

<script type="text/javascript">
let str = sessionStorage.getItem("login");	
let json = JSON.parse(str);

const url = new URL(location.href);
const urlParams = url.searchParams;
let seq = urlParams.get("seq");

//alert("seq: " + seq);
commentList();

$.ajax({
	url:"http://localhost:3000/bbsdetail",
	type:"get",
	data:{ "seq":seq },
	success:function(bbs){
		//alert('success');
		//alert(JSON.stringify(bbs));
		
		$("#id").text(bbs.id);
		$("#title").text(bbs.title);
		$("#wdate").text(bbs.wdate);
		$("#readcount").text(bbs.readcount);
		$("#content").text(bbs.content);
		
		let login = JSON.parse(sessionStorage.getItem("login"));
		if(bbs.id != login.id){
			$("#bbsupdate").hide();
			$("#bbsdelete").hide();
		}
		
	},
	error:function(){
		alert('error');
	}
	
});

$("#bbsanswer").click(function () {	
	location.href = "bbsanswer.html?seq=" + seq;
});

$("#bbsupdate").click(function () {	
	location.href = "bbsupdate.html?seq=" + seq;
});

$("#bbsdelete").click(function () {	
	$.ajax({
		url:"http://localhost:3000/bbsdelete",
		type:"get",
		data:{ "seq":seq },
		success:function(msg){
			if(msg == "OK"){
				alert("삭제되었습니다");
				location.href = "bbslist.html";
			}else{
				alert("삭제되지 않았습니다");
			}
		},
		error:function(){
			alert('error');
		}
	})
});

$("#commentBtn").click(function () {
	commentWrite();	
});

function commentWrite() {
	
	if($("#commentContent").val().trim() == ""){
		alert("코멘트를 작성해 주세요");
		return;
	}
	
	$.ajax({
		url:"http://localhost:3000/commentWrite",
		type:"get",
		data:{ "seq":seq, "id":json.id, "content":$("#commentContent").val() },
		success:function(msg){			
			commentList();
			$("#commentContent").val("");
		},
		error:function(){
			alert('error');
		}
	})	
}

function commentList() {
	$.ajax({
		url:"http://localhost:3000/getCommentList",
		type:"get",
		data:{ "seq":seq },
		success:function(list){
			
			$("#tbody").html("");
			
			$.each(list, function (i, item) {
				let str = "<tr class='table-info'>" +
				 				"<td>작성자: " + item.id +"</td>" +
								"<td >작성일: " + item.wdate + "</td>" + 
						  "</tr>" +
						  "<tr>" +
								"<td colspan='2'>" + item.content + "</td>" +
						  "</tr>";						  
				$("#tbody").append(str);							
			});
		},
		error:function(){
			alert('error');
		}
	})	
}




</script>

</body>
</html>

 

bbsupdate.html (작성한글 수정)
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>

<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
</head>
<body>

<h2>글 수정</h2>

<form action="">
<div id="app" class="container">
<table class="table table-bordered" border="1">
<col width="200"><col width="500">
<tr>
	<th>작성자</th>
	<td>
		<input type="text" id="id" readonly="readonly">
	</td>
</tr>

<tr>
	<th>제목</th>
	<td>
		<input type="text" id="title" size="80px">
	</td>
</tr>

<tr>
	<th>내용</th>
	<td>
		<textarea rows="20" class="form-control" id="content"></textarea>
	</td>
</tr>

</table>
	<button type="button" id="bbsupdate" class="btn btn-secondary">수정완료</button>
</div>
</form>



<script type="text/javascript">
let str = sessionStorage.getItem("login");	
let json = JSON.parse(str);

const url = new URL(location.href);
const urlParams = url.searchParams;
let seq = urlParams.get("seq");

$("#id").val(json.id);

$.ajax({
	url:"http://localhost:3000/bbsdetail",
	type:"get",
	data:{ "seq":seq },
	success:function(bbs){
		//alert('success');
		$("#id").val(bbs.id);
		$("#title").val(bbs.title);		
		$("#content").val(bbs.content);
	},
	error:function(){
		alert('error');
	}
});

$("#bbsupdate").click(function () {
	$.ajax({
		url:"http://localhost:3000/bbsupdate",
		type:"get",
		data:{ "seq":seq, "title":$("#title").val(), "content":$("#content").val() },
		success:function(msg){
			if(msg == "OK"){
				alert('정상적으로 수정되었습니다');
				location.href = "bbslist.html";
			}else{
				alert('수정되지 않았습니다');
			}			
		},
		error:function(){
			alert('error');
		}	
	});
});
</script>

</body>
</html>

 

이제 이해할 일만 남았다

Comments