rest controller practice

This commit is contained in:
haerong22
2021-03-12 18:24:49 +09:00
parent e9b0716fd0
commit 5c9e2a9cc0
79 changed files with 3354 additions and 0 deletions

37
rest-controller-practice/.gitignore vendored Normal file
View File

@@ -0,0 +1,37 @@
HELP.md
.gradle
build/
!gradle/wrapper/gradle-wrapper.jar
!**/src/main/**/build/
!**/src/test/**/build/
### STS ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
bin/
!**/src/main/**/bin/
!**/src/test/**/bin/
### IntelliJ IDEA ###
.idea
*.iws
*.iml
*.ipr
out/
!**/src/main/**/out/
!**/src/test/**/out/
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
### VS Code ###
.vscode/

View File

@@ -0,0 +1,58 @@
plugins {
id 'org.springframework.boot' version '2.4.2'
id 'io.spring.dependency-management' version '1.0.11.RELEASE'
id 'org.asciidoctor.convert' version '1.5.8'
id 'java'
}
group = 'com.example.jpa'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
}
ext {
set('snippetsDir', file("build/generated-snippets"))
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation("org.springframework.boot:spring-boot-starter-validation")
// https://mvnrepository.com/artifact/com.auth0/java-jwt
implementation group: 'com.auth0', name: 'java-jwt', version: '3.13.0'
// https://mvnrepository.com/artifact/org.qlrm/qlrm
implementation group: 'org.qlrm', name: 'qlrm', version: '2.1.1'
compileOnly 'org.projectlombok:lombok'
runtimeOnly 'com.h2database:h2'
annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.springframework.restdocs:spring-restdocs-mockmvc'
testImplementation 'org.springframework.security:spring-security-test'
}
test {
outputs.dir snippetsDir
useJUnitPlatform()
}
asciidoctor {
inputs.dir snippetsDir
dependsOn test
}

Binary file not shown.

View File

@@ -0,0 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.2-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

184
rest-controller-practice/gradlew vendored Normal file
View File

@@ -0,0 +1,184 @@
#!/usr/bin/env sh
#
# Copyright 2015 the original author or authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ]; do
ls=$(ls -ld "$PRG")
link=$(expr "$ls" : '.*-> \(.*\)$')
if expr "$link" : '/.*' >/dev/null; then
PRG="$link"
else
PRG=$(dirname "$PRG")"/$link"
fi
done
SAVED="$(pwd)"
cd "$(dirname \"$PRG\")/" >/dev/null
APP_HOME="$(pwd -P)"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=$(basename "$0")
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn() {
echo "$*"
}
die() {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "$(uname)" in
CYGWIN*)
cygwin=true
;;
Darwin*)
darwin=true
;;
MINGW*)
msys=true
;;
NONSTOP*)
nonstop=true
;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ]; then
if [ -x "$JAVA_HOME/jre/sh/java" ]; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ]; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ]; then
MAX_FD_LIMIT=$(ulimit -H -n)
if [ $? -eq 0 ]; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ]; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ]; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if [ "$cygwin" = "true" -o "$msys" = "true" ]; then
APP_HOME=$(cygpath --path --mixed "$APP_HOME")
CLASSPATH=$(cygpath --path --mixed "$CLASSPATH")
JAVACMD=$(cygpath --unix "$JAVACMD")
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=$(find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null)
SEP=""
for dir in $ROOTDIRSRAW; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ]; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@"; do
CHECK=$(echo "$arg" | egrep -c "$OURCYGPATTERN" -)
CHECK2=$(echo "$arg" | egrep -c "^-") ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ]; then ### Added a condition
eval $(echo args$i)=$(cygpath --path --ignore --mixed "$arg")
else
eval $(echo args$i)="\"$arg\""
fi
i=$(expr $i + 1)
done
case $i in
0) set -- ;;
1) set -- "$args0" ;;
2) set -- "$args0" "$args1" ;;
3) set -- "$args0" "$args1" "$args2" ;;
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Escape application args
save() {
for i; do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/"; done
echo " "
}
APP_ARGS=$(save "$@")
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
exec "$JAVACMD" "$@"

89
rest-controller-practice/gradlew.bat vendored Normal file
View File

@@ -0,0 +1,89 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

View File

@@ -0,0 +1 @@
rootProject.name = 'rest-controller'

View File

@@ -0,0 +1,44 @@
package com.example.restcontroller;
import com.example.restcontroller.board.exception.BoardTypeNotFoundException;
import com.example.restcontroller.notice.exception.AlreadyDeletedException;
import com.example.restcontroller.notice.exception.DuplicateNoticeException;
import com.example.restcontroller.notice.exception.NoticeNotFoundException;
import com.example.restcontroller.user.exception.ExistsEmailException;
import com.example.restcontroller.user.exception.PasswordNotMatchException;
import com.example.restcontroller.user.exception.UserNotFoundException;
import com.example.restcontroller.user.model.ResponseMessage;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler({ NoticeNotFoundException.class,
DuplicateNoticeException.class,
UserNotFoundException.class,
ExistsEmailException.class,
PasswordNotMatchException.class,
BoardTypeNotFoundException.class })
public ResponseEntity<?> badRequest(RuntimeException e) {
return new ResponseEntity<>(ResponseMessage.fail(e.getMessage()), HttpStatus.BAD_REQUEST);
}
@ExceptionHandler(DataIntegrityViolationException.class)
public ResponseEntity<?> internalServerError(DataIntegrityViolationException e) {
return new ResponseEntity<>("회원 가입 실패", HttpStatus.INTERNAL_SERVER_ERROR);
}
@ExceptionHandler(AlreadyDeletedException.class)
public ResponseEntity<?> ok(AlreadyDeletedException e) {
return new ResponseEntity<>(e.getMessage(), HttpStatus.OK);
}
@ExceptionHandler(Exception.class)
public ResponseEntity<?> exception(Exception e) {
return new ResponseEntity<>(e.getMessage(), HttpStatus.OK);
}
}

View File

@@ -0,0 +1,13 @@
package com.example.restcontroller;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class RestControllerApplication {
public static void main(String[] args) {
SpringApplication.run(RestControllerApplication.class, args);
}
}

View File

@@ -0,0 +1,201 @@
package com.example.restcontroller.board.controller;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.example.restcontroller.board.entity.BoardType;
import com.example.restcontroller.board.model.*;
import com.example.restcontroller.board.service.BoardService;
import com.example.restcontroller.common.model.ResponseResult;
import com.example.restcontroller.notice.model.ResponseError;
import com.example.restcontroller.user.model.ResponseMessage;
import com.example.restcontroller.util.JWTUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import java.util.List;
@RequiredArgsConstructor
@RestController
public class ApiBoardController {
private final BoardService boardService;
@PostMapping("/api/board/type")
public ResponseEntity<?> chapter3_1(@RequestBody @Valid BoardTypeInput boardTypeInput, BindingResult bindingResult) {
if (bindingResult.hasFieldErrors()) {
List<ResponseError> responseErrors = ResponseError.of(bindingResult.getFieldErrors());
ResponseEntity.badRequest().body(ResponseMessage.fail("입력값이 정확하지 않습니다.", responseErrors));
}
ServiceResult result = boardService.addBoard(boardTypeInput);
if (!result.isResult()) {
return ResponseEntity.ok().body(ResponseMessage.fail(result.getMessage()));
}
return ResponseEntity.ok().body(ResponseMessage.success());
}
@PutMapping("/api/board/type/{id}")
public ResponseEntity<?> chapter3_2(@PathVariable Long id,
@RequestBody @Valid BoardTypeInput boardTypeInput, BindingResult bindingResult) {
if (bindingResult.hasFieldErrors()) {
List<ResponseError> responseErrors = ResponseError.of(bindingResult.getFieldErrors());
ResponseEntity.badRequest().body(ResponseMessage.fail("입력값이 정확하지 않습니다.", responseErrors));
}
System.out.println(boardTypeInput.getName());
ServiceResult result = boardService.updateBoard(id, boardTypeInput);
if (!result.isResult()) {
return ResponseEntity.ok().body(ResponseMessage.fail(result.getMessage()));
}
return ResponseEntity.ok().body(ResponseMessage.success());
}
@DeleteMapping("/api/board/type/{id}")
public ResponseEntity<?> chapter3_3(@PathVariable Long id) {
ServiceResult result = boardService.deleteBoard(id);
if (!result.isResult()) {
return ResponseEntity.ok().body(ResponseMessage.fail(result.getMessage()));
}
return ResponseEntity.ok().body(ResponseMessage.success());
}
@GetMapping("/api/board/type")
public ResponseEntity<?> chapter3_4() {
List<BoardType> boardTypeList = boardService.getBoardTypeList();
return ResponseEntity.ok().body(ResponseMessage.success(boardTypeList));
}
@PatchMapping("/api/board/type/{id}/using")
public ResponseEntity<?> chapter3_5(@PathVariable Long id, @RequestBody BoardTypeUsing boardTypeUsing) {
ServiceResult result = boardService.setBoardTypeUsing(id, boardTypeUsing);
if (!result.isResult()) {
return ResponseEntity.ok().body(ResponseMessage.fail(result.getMessage()));
}
return ResponseEntity.ok().body(ResponseMessage.success());
}
@GetMapping("/api/board/type/count")
public ResponseEntity<?> chapter3_6() {
List<BoardTypeCount> list = boardService.getBoardTypeCount();
return ResponseEntity.ok().body(ResponseMessage.success(list));
}
@PatchMapping("/api/board/{id}/top")
public ResponseEntity<?> chapter3_7(@PathVariable Long id) {
ServiceResult result = boardService.setBoardTop(id, true);
if (!result.isResult()) {
return ResponseEntity.ok().body(ResponseMessage.fail(result.getMessage()));
}
return ResponseEntity.ok().body(ResponseMessage.success());
}
@PatchMapping("/api/board/{id}/top/clear")
public ResponseEntity<?> chapter3_8(@PathVariable Long id) {
ServiceResult result = boardService.setBoardTop(id, false);
if (!result.isResult()) {
return ResponseEntity.ok().body(ResponseMessage.fail(result.getMessage()));
}
return ResponseEntity.ok().body(ResponseMessage.success());
}
@PatchMapping("/api/board/{id}/publish")
public ResponseEntity<?> chapter3_9(@PathVariable Long id, @RequestBody BoardPeriod boardPeriod) {
ServiceResult result = boardService.setBoardPeriod(id, boardPeriod);
if (!result.isResult()) {
return ResponseResult.fail(result.getMessage());
}
return ResponseResult.success();
}
@PutMapping("/api/board/{id}/hits")
public ResponseEntity<?> chapter3_10(@PathVariable Long id, @RequestHeader("TOKEN") String token) {
String email = "";
try {
email = JWTUtils.getIssuer(token);
} catch (JWTVerificationException e) {
return ResponseResult.fail("토큰 정보가 정확하지 않습니다.");
}
ServiceResult result = boardService.setBoardHits(id, email);
if (result.isFail()) {
return ResponseResult.fail(result.getMessage());
}
return ResponseResult.success();
}
@PutMapping("/api/board/{id}/like")
public ResponseEntity<?> chapter3_11(@PathVariable Long id, @RequestHeader("TOKEN") String token) {
String email = "";
try {
email = JWTUtils.getIssuer(token);
} catch (JWTVerificationException e) {
return ResponseResult.fail("토큰 정보가 정확하지 않습니다.");
}
ServiceResult result = boardService.setBoardLike(id, email);
return ResponseResult.result(result);
}
@PutMapping("/api/board/{id}/unlike")
public ResponseEntity<?> chapter3_12(@PathVariable Long id, @RequestHeader("TOKEN") String token) {
String email = "";
try {
email = JWTUtils.getIssuer(token);
} catch (JWTVerificationException e) {
return ResponseResult.fail("토큰 정보가 정확하지 않습니다.");
}
ServiceResult result = boardService.setBoardUnLike(id, email);
return ResponseResult.result(result);
}
@PutMapping("/api/board/{id}/report")
public ResponseEntity<?> chapter3_13(@PathVariable Long id,
@RequestHeader("TOKEN") String token,
@RequestBody BoardReportInput boardReportInput) {
String email = "";
try {
email = JWTUtils.getIssuer(token);
} catch (JWTVerificationException e) {
return ResponseResult.fail("토큰 정보가 정확하지 않습니다.");
}
ServiceResult result = boardService.addReport(id, email, boardReportInput);
return ResponseResult.result(result);
}
}

View File

@@ -0,0 +1,53 @@
package com.example.restcontroller.board.entity;
import com.example.restcontroller.user.entity.User;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.*;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Entity
public class Board {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne
@JoinColumn
private User user;
@ManyToOne
@JoinColumn
private BoardType boardType;
@JsonIgnore
@OneToMany(mappedBy = "board")
List<BoardHits> boardHitsList = new ArrayList<>();
@JsonIgnore
@OneToMany(mappedBy = "board")
List<BoardLike> boardLikeList = new ArrayList<>();
private String title;
private String content;
private boolean topYn;
private LocalDateTime regDate;
private LocalDate publishStartDate;
private LocalDate publishEndDate;
}

View File

@@ -0,0 +1,31 @@
package com.example.restcontroller.board.entity;
import com.example.restcontroller.user.entity.User;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.*;
import java.time.LocalDateTime;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Entity
public class BoardHits {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne
@JoinColumn
private Board board;
@ManyToOne
@JoinColumn
private User user;
private LocalDateTime regDate;
}

View File

@@ -0,0 +1,31 @@
package com.example.restcontroller.board.entity;
import com.example.restcontroller.user.entity.User;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.*;
import java.time.LocalDateTime;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Entity
public class BoardLike {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne
@JoinColumn
private Board board;
@ManyToOne
@JoinColumn
private User user;
private LocalDateTime regDate;
}

View File

@@ -0,0 +1,41 @@
package com.example.restcontroller.board.entity;
import com.example.restcontroller.user.entity.User;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.*;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Entity
public class BoardReport {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
// 신고자
private Long userId;
private String userName;
private String userEmail;
// 신고 게시글
private Long boardId;
private Long boardUserId;
private String boardTitle;
private String boardContents;
private LocalDateTime boardRegDate;
// 신고내용
private String comments;
private LocalDateTime regDate;
}

View File

@@ -0,0 +1,35 @@
package com.example.restcontroller.board.entity;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.*;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Entity
public class BoardType {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String boardName;
private LocalDateTime regDate;
private LocalDateTime updateDate;
private boolean usingYn;
@JsonIgnore
@OneToMany(mappedBy = "boardType")
List<Board> boardList = new ArrayList<>();
}

View File

@@ -0,0 +1,7 @@
package com.example.restcontroller.board.exception;
public class BoardTypeNotFoundException extends RuntimeException {
public BoardTypeNotFoundException(String message) {
super(message);
}
}

View File

@@ -0,0 +1,18 @@
package com.example.restcontroller.board.model;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDate;
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Data
public class BoardPeriod {
private LocalDate startDate;
private LocalDate endDate;
}

View File

@@ -0,0 +1,15 @@
package com.example.restcontroller.board.model;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Data
public class BoardReportInput {
private String comments;
}

View File

@@ -0,0 +1,34 @@
package com.example.restcontroller.board.model;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.math.BigInteger;
import java.sql.Timestamp;
import java.time.LocalDateTime;
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Data
public class BoardTypeCount {
private Long id;
private String boardName;
private LocalDateTime regDate;
private boolean usingYn;
private Long boardCount;
public static BoardTypeCount of(Object[] arr) {
return BoardTypeCount.builder()
.id(((BigInteger) arr[0]).longValue())
.boardName((String) arr[1])
.regDate(((Timestamp) arr[2]).toLocalDateTime())
.usingYn((Boolean) arr[3])
.boardCount(((BigInteger) arr[4]).longValue())
.build();
}
}

View File

@@ -0,0 +1,18 @@
package com.example.restcontroller.board.model;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.NotBlank;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class BoardTypeInput {
@NotBlank(message = "게시판 제목은 필수 항목입니다.")
private String name;
}

View File

@@ -0,0 +1,15 @@
package com.example.restcontroller.board.model;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class BoardTypeUsing {
private boolean usingYn;
}

View File

@@ -0,0 +1,33 @@
package com.example.restcontroller.board.model;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class ServiceResult {
private boolean result;
private String message;
public static ServiceResult fail(String message) {
return ServiceResult.builder()
.result(false)
.message(message)
.build();
}
public static ServiceResult success() {
return ServiceResult.builder()
.result(true)
.build();
}
public boolean isFail() {
return !result;
}
}

View File

@@ -0,0 +1,13 @@
package com.example.restcontroller.board.repository;
import com.example.restcontroller.board.entity.Board;
import com.example.restcontroller.board.entity.BoardHits;
import com.example.restcontroller.user.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface BoardHitsRepository extends JpaRepository<BoardHits, Long> {
long countByBoardAndUser(Board board, User user);
}

View File

@@ -0,0 +1,17 @@
package com.example.restcontroller.board.repository;
import com.example.restcontroller.board.entity.Board;
import com.example.restcontroller.board.entity.BoardHits;
import com.example.restcontroller.board.entity.BoardLike;
import com.example.restcontroller.user.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface BoardLikeRepository extends JpaRepository<BoardLike, Long> {
long countByBoardAndUser(Board board, User user);
void deleteByBoardAndUser(Board board, User user);
}

View File

@@ -0,0 +1,9 @@
package com.example.restcontroller.board.repository;
import com.example.restcontroller.board.entity.BoardReport;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface BoardReportRepository extends JpaRepository<BoardReport, Long> {
}

View File

@@ -0,0 +1,12 @@
package com.example.restcontroller.board.repository;
import com.example.restcontroller.board.entity.Board;
import com.example.restcontroller.board.entity.BoardType;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface BoardRepository extends JpaRepository<Board, Long> {
long countByBoardType(BoardType boardType);
}

View File

@@ -0,0 +1,35 @@
package com.example.restcontroller.board.repository;
import com.example.restcontroller.board.model.BoardTypeCount;
import lombok.RequiredArgsConstructor;
import org.qlrm.mapper.JpaResultMapper;
import org.springframework.stereotype.Repository;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import java.util.List;
import java.util.stream.Collectors;
@RequiredArgsConstructor
@Repository
public class BoardTypeCustomRepository {
private final EntityManager em;
public List<BoardTypeCount> getBoardTypeCount() {
String sql = "select bt.id, bt.board_name, bt.reg_date, bt.using_yn, " +
"(select count(*) from board b where b.board_type_id = bt.id) as board_count " +
"from board_type bt where bt.using_yn=true";
// SELECT bt.id, bt.board_name, bt.reg_date, bt.using_yn, ct.count FROM (select board_type_id, count(*) count from board group by board_type_id) ct left outer join board_type bt on bt.id=ct.board_type_id;
// List<BoardTypeCount> list = em.createNativeQuery(sql).getResultList();
List<Object[]> resultList = em.createNativeQuery(sql).getResultList();
List<BoardTypeCount> list = resultList.stream().map(BoardTypeCount::of).collect(Collectors.toList());
// // 라이브러리 사용
// Query nativeQuery = em.createNativeQuery(sql);
// JpaResultMapper jpaResultMapper = new JpaResultMapper();
// List<BoardTypeCount> list = jpaResultMapper.list(nativeQuery, BoardTypeCount.class);
return list;
}
}

View File

@@ -0,0 +1,12 @@
package com.example.restcontroller.board.repository;
import com.example.restcontroller.board.entity.BoardType;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.Optional;
@Repository
public interface BoardTypeRepository extends JpaRepository<BoardType, Long> {
int countByBoardName(String boardName);
}

View File

@@ -0,0 +1,33 @@
package com.example.restcontroller.board.service;
import com.example.restcontroller.board.entity.BoardType;
import com.example.restcontroller.board.model.*;
import java.util.List;
public interface BoardService {
ServiceResult addBoard(BoardTypeInput boardTypeInput);
ServiceResult updateBoard(Long id, BoardTypeInput boardTypeInput);
ServiceResult deleteBoard(Long id);
List<BoardType> getBoardTypeList();
ServiceResult setBoardTypeUsing(Long id, BoardTypeUsing boardTypeUsing);
List<BoardTypeCount> getBoardTypeCount();
ServiceResult setBoardTop(Long id, boolean topYn);
ServiceResult setBoardPeriod(Long id, BoardPeriod boardPeriod);
ServiceResult setBoardHits(Long id, String email);
ServiceResult setBoardLike(Long id, String email);
ServiceResult setBoardUnLike(Long id, String email);
ServiceResult addReport(Long id, String email, BoardReportInput boardReportInput);
}

View File

@@ -0,0 +1,241 @@
package com.example.restcontroller.board.service;
import com.example.restcontroller.board.entity.*;
import com.example.restcontroller.board.exception.BoardTypeNotFoundException;
import com.example.restcontroller.board.model.*;
import com.example.restcontroller.board.repository.*;
import com.example.restcontroller.user.entity.User;
import com.example.restcontroller.user.repository.UserRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
@RequiredArgsConstructor
@Service
@Transactional(readOnly = true)
public class BoardServiceImpl implements BoardService {
private final BoardTypeRepository boardTypeRepository;
private final BoardRepository boardRepository;
private final BoardTypeCustomRepository boardTypeCustomRepository;
private final BoardHitsRepository boardHitsRepository;
private final UserRepository userRepository;
private final BoardLikeRepository boardLikeRepository;
private final BoardReportRepository boardReportRepository;
@Transactional
@Override
public ServiceResult addBoard(BoardTypeInput boardTypeInput) {
int result = boardTypeRepository.countByBoardName(boardTypeInput.getName());
if (result > 0) {
return ServiceResult.fail("이미 동일한 게시판명이 존재합니다.");
}
BoardType boardType = BoardType.builder()
.boardName(boardTypeInput.getName())
.regDate(LocalDateTime.now())
.build();
boardTypeRepository.save(boardType);
return ServiceResult.success();
}
@Transactional
@Override
public ServiceResult updateBoard(Long id, BoardTypeInput boardTypeInput) {
int result = boardTypeRepository.countByBoardName(boardTypeInput.getName());
if (result > 0) {
return ServiceResult.fail("이미 동일한 게시판명이 존재합니다.");
}
BoardType boardTypeEntity = boardTypeRepository.findById(id)
.orElseThrow(() -> new BoardTypeNotFoundException("삭제할 게시판 타입이 없습니다."));
boardTypeEntity.setBoardName(boardTypeInput.getName());
boardTypeEntity.setUpdateDate(LocalDateTime.now());
// boardTypeRepository.save(boardTypeEntity);
return ServiceResult.success();
}
@Transactional
@Override
public ServiceResult deleteBoard(Long id) {
BoardType boardType = boardTypeRepository.findById(id)
.orElseThrow(() -> new BoardTypeNotFoundException("삭제할 게시판 타입이 없습니다."));
if (boardRepository.countByBoardType(boardType) > 0 ) {
return ServiceResult.fail("삭제할 게시판타입의 게시글이 존재합니다.");
}
boardTypeRepository.delete(boardType);
return ServiceResult.success();
}
@Override
public List<BoardType> getBoardTypeList() {
return boardTypeRepository.findAll();
}
@Transactional
@Override
public ServiceResult setBoardTypeUsing(Long id, BoardTypeUsing boardTypeUsing) {
BoardType boardType = boardTypeRepository.findById(id)
.orElseThrow(() -> new BoardTypeNotFoundException("게시판 타입이 없습니다."));
boardType.setUsingYn(boardTypeUsing.isUsingYn());
return ServiceResult.success();
}
@Override
public List<BoardTypeCount> getBoardTypeCount() {
return boardTypeCustomRepository.getBoardTypeCount();
}
@Transactional
@Override
public ServiceResult setBoardTop(Long id, boolean topYn) {
Optional<Board> board = boardRepository.findById(id);
if (!board.isPresent()) {
return ServiceResult.fail("게시글이 존재하지 않습니다");
}
Board boardEntity = board.get();
if (boardEntity.isTopYn() == topYn) {
String msg = topYn ? "이미 게시글이 최상단에 배치되어 있습니다." : "이미 게시글이 최상단 배치가 해제되어 있습니다.";
return ServiceResult.fail(msg);
}
boardEntity.setTopYn(topYn);
return ServiceResult.success();
}
@Transactional
@Override
public ServiceResult setBoardPeriod(Long id, BoardPeriod boardPeriod) {
Optional<Board> board = boardRepository.findById(id);
if (!board.isPresent()) {
return ServiceResult.fail("게시글이 존재하지 않습니다");
}
Board boardEntity = board.get();
boardEntity.setPublishStartDate(boardPeriod.getStartDate());
boardEntity.setPublishEndDate(boardPeriod.getEndDate());
return ServiceResult.success();
}
@Transactional
@Override
public ServiceResult setBoardHits(Long id, String email) {
Optional<Board> board = boardRepository.findById(id);
if (!board.isPresent()) {
return ServiceResult.fail("게시글이 존재하지 않습니다");
}
Board boardEntity = board.get();
Optional<User> optionalUser = userRepository.findByEmail(email);
if (!optionalUser.isPresent()) {
return ServiceResult.fail("회원 정보가 존재하지 않습니다");
}
User userEntity = optionalUser.get();
if (boardHitsRepository.countByBoardAndUser(boardEntity, userEntity) > 0) {
return ServiceResult.fail("이미 조회수가 있습니다.");
}
boardHitsRepository.save(BoardHits.builder()
.board(boardEntity)
.user(userEntity)
.regDate(LocalDateTime.now())
.build());
return ServiceResult.success();
}
@Transactional
@Override
public ServiceResult setBoardLike(Long id, String email) {
Optional<Board> board = boardRepository.findById(id);
if (!board.isPresent()) {
return ServiceResult.fail("게시글이 존재하지 않습니다");
}
Board boardEntity = board.get();
Optional<User> optionalUser = userRepository.findByEmail(email);
if (!optionalUser.isPresent()) {
return ServiceResult.fail("회원 정보가 존재하지 않습니다");
}
User userEntity = optionalUser.get();
if (boardLikeRepository.countByBoardAndUser(boardEntity, userEntity) > 0) {
return ServiceResult.fail("이미 좋아요를 누른 게시글 입니다.");
}
boardLikeRepository.save(BoardLike.builder()
.board(boardEntity)
.user(userEntity)
.regDate(LocalDateTime.now())
.build());
return ServiceResult.success();
}
@Transactional
@Override
public ServiceResult setBoardUnLike(Long id, String email) {
Optional<Board> board = boardRepository.findById(id);
if (!board.isPresent()) {
return ServiceResult.fail("게시글이 존재하지 않습니다");
}
Board boardEntity = board.get();
Optional<User> optionalUser = userRepository.findByEmail(email);
if (!optionalUser.isPresent()) {
return ServiceResult.fail("회원 정보가 존재하지 않습니다");
}
User userEntity = optionalUser.get();
if (boardLikeRepository.countByBoardAndUser(boardEntity, userEntity) < 1) {
return ServiceResult.fail("좋아요한 내용이 없습니다.");
}
boardLikeRepository.deleteByBoardAndUser(boardEntity, userEntity);
return ServiceResult.success();
}
@Override
public ServiceResult addReport(Long id, String email, BoardReportInput boardReportInput) {
Optional<Board> board = boardRepository.findById(id);
if (!board.isPresent()) {
return ServiceResult.fail("게시글이 존재하지 않습니다");
}
Board boardEntity = board.get();
Optional<User> optionalUser = userRepository.findByEmail(email);
if (!optionalUser.isPresent()) {
return ServiceResult.fail("회원 정보가 존재하지 않습니다");
}
User userEntity = optionalUser.get();
BoardReport boardReport = BoardReport.builder()
.userId(userEntity.getId())
.userName(userEntity.getUserName())
.userEmail(userEntity.getEmail())
.boardId(boardEntity.getId())
.boardUserId(boardEntity.getUser().getId())
.boardTitle(boardEntity.getTitle())
.boardContents(boardEntity.getContent())
.boardRegDate(boardEntity.getRegDate())
.comments(boardReportInput.getComments())
.regDate(LocalDateTime.now())
.build();
boardReportRepository.save(boardReport);
return ServiceResult.success();
}
}

View File

@@ -0,0 +1,24 @@
package com.example.restcontroller.common.model;
import com.example.restcontroller.board.model.ServiceResult;
import com.example.restcontroller.user.model.ResponseMessage;
import org.springframework.http.ResponseEntity;
public class ResponseResult {
public static ResponseEntity<?> fail(String message) {
return ResponseEntity.badRequest().body(ResponseMessage.fail(message));
}
public static ResponseEntity<?> success() {
return ResponseEntity.ok().body(ResponseMessage.success());
}
public static ResponseEntity<?> result(ServiceResult result) {
if (result.isFail()) {
return fail(result.getMessage());
}
return success();
}
}

View File

@@ -0,0 +1,23 @@
package com.example.restcontroller.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
http.headers().frameOptions().sameOrigin();
http.authorizeRequests()
.anyRequest().permitAll();
}
}

View File

@@ -0,0 +1,27 @@
package com.example.restcontroller.hello;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class StartController {
@RequestMapping(value = "/first-url", method = RequestMethod.GET)
public void chapter1_1() {
}
@ResponseBody
@RequestMapping("/helloworld")
public String chapter1_2() {
return "hello world";
}
@ResponseBody
@GetMapping("/hello-spring")
public String chapter1_3() {
return "hello spring";
}
}

View File

@@ -0,0 +1,18 @@
package com.example.restcontroller.hello;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class StartRestController {
@GetMapping("/hello-rest")
public String chapter1_4() {
return "\"hello rest\"";
}
@GetMapping("/api/helloworld")
public String chapter1_5() {
return "hello rest api";
}
}

View File

@@ -0,0 +1,333 @@
package com.example.restcontroller.notice.controller;
import com.example.restcontroller.notice.entity.Notice;
import com.example.restcontroller.notice.exception.AlreadyDeletedException;
import com.example.restcontroller.notice.exception.DuplicateNoticeException;
import com.example.restcontroller.notice.exception.NoticeNotFoundException;
import com.example.restcontroller.notice.model.NoticeDeleteInput;
import com.example.restcontroller.notice.model.NoticeInput;
import com.example.restcontroller.notice.model.NoticeModel;
import com.example.restcontroller.notice.model.ResponseError;
import com.example.restcontroller.notice.repository.NoticeRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
@RequiredArgsConstructor
@RestController
public class ApiNoticeController {
private final NoticeRepository noticeRepository;
@GetMapping("/api/notice")
public String chapter1_6() {
return "공지사항입니다.";
}
@GetMapping("/api/notice2")
public NoticeModel chapter1_7() {
return NoticeModel.builder()
.id(1L)
.title("공지사항입니다.")
.contents("공지사항 내용 입니다.")
.regDate(LocalDateTime.now())
.build();
}
@GetMapping("/api/notice3")
public List<NoticeModel> chapter1_8() {
List<NoticeModel> noticeList = new ArrayList<>();
noticeList.add(NoticeModel.builder()
.id(1L)
.title("공지사항입니다.")
.contents("공지사항 내용입니다.")
.regDate(LocalDateTime.of(2021, 1, 30, 0, 0))
.build());
noticeList.add(NoticeModel.builder()
.id(2L)
.title("두번째 공지사항입니다.")
.contents("두번째 공지사항 내용입니다.")
.regDate(LocalDateTime.of(2021, 1, 31, 0, 0))
.build());
return noticeList;
}
@GetMapping("/api/notice5")
public List<NoticeModel> chapter1_9() {
return new ArrayList<>();
}
@GetMapping("/api/notice/count")
public Integer chapter1_10() {
List<NoticeModel> noticeList = new ArrayList<>();
noticeList.add(new NoticeModel());
noticeList.add(new NoticeModel());
noticeList.add(new NoticeModel());
return noticeList.size();
}
@PostMapping("/api/notice")
public NoticeModel chapter1_11(@RequestParam String title,
@RequestParam String contents) {
return NoticeModel.builder()
.id(1L)
.title(title)
.contents(contents)
.regDate(LocalDateTime.now())
.build();
}
@PostMapping("/api/notice2")
public NoticeModel chapter1_12(NoticeModel noticeModel) {
return noticeModel
.setId(2L)
.setRegDate(LocalDateTime.now());
}
@PostMapping("/api/notice3")
public NoticeModel chapter1_13(@RequestBody NoticeModel noticeModel) {
return noticeModel
.setId(3L)
.setRegDate(LocalDateTime.now());
}
@PostMapping("/api/notice4")
public Notice chapter1_14(@RequestBody NoticeInput noticeInput) {
return noticeRepository.save(Notice.builder()
.title(noticeInput.getTitle())
.contents(noticeInput.getContents())
.regDate(LocalDateTime.now())
.build());
}
@PostMapping("/api/notice5")
public Notice chapter1_15(@RequestBody NoticeInput noticeInput) {
return noticeRepository.save(Notice.builder()
.title(noticeInput.getTitle())
.contents(noticeInput.getContents())
.regDate(LocalDateTime.now())
.build());
}
@GetMapping("/api/notice/{id}")
public Notice chapter1_16(@PathVariable Long id) {
return noticeRepository.findById(id).orElseGet(() -> null);
}
@PutMapping("/api/notice/{id}")
public Notice chapter1_17(@PathVariable Long id, @RequestBody NoticeInput noticeInput) {
Notice noticeEntity = noticeRepository.findById(id)
.orElseThrow(() -> new IllegalArgumentException("아이디 없음"));
noticeEntity
.setTitle(noticeInput.getTitle())
.setContents(noticeInput.getContents())
.setUpdateDate(LocalDateTime.now());
noticeRepository.save(noticeEntity);
return noticeEntity;
}
@PutMapping("/api/notice2/{id}")
public Notice chapter1_18(@PathVariable Long id, @RequestBody NoticeInput noticeInput) {
Notice noticeEntity = noticeRepository.findById(id)
.orElseThrow(() -> new NoticeNotFoundException("공지사항의 글이 존재하지 않습니다."));
noticeEntity
.setTitle(noticeInput.getTitle())
.setContents(noticeInput.getContents());
noticeRepository.save(noticeEntity);
return noticeEntity;
}
@PutMapping("/api/notice3/{id}")
public Notice chapter1_19(@PathVariable Long id, @RequestBody NoticeInput noticeInput) {
Notice noticeEntity = noticeRepository.findById(id)
.orElseThrow(() -> new NoticeNotFoundException("공지사항의 글이 존재하지 않습니다."));
noticeEntity
.setTitle(noticeInput.getTitle())
.setContents(noticeInput.getContents())
.setUpdateDate(LocalDateTime.now());
noticeRepository.save(noticeEntity);
return noticeEntity;
}
@PatchMapping("/api/notice/{id}/hits")
public void chapter1_20(@PathVariable Long id) {
Notice noticeEntity = noticeRepository.findById(id)
.orElseThrow(() -> new NoticeNotFoundException("공지사항의 글이 존재하지 않습니다."));
noticeEntity.setHits(noticeEntity.getHits() + 1);
noticeRepository.save(noticeEntity);
}
@DeleteMapping("/api/notice/{id}")
public void chapter1_21(@PathVariable Long id) {
noticeRepository.deleteById(id);
}
@DeleteMapping("/api/notice2/{id}")
public void chapter1_22(@PathVariable Long id) {
Notice noticeEntity = noticeRepository.findById(id)
.orElseThrow(() -> new NoticeNotFoundException("공지사항의 글이 존재하지 않습니다."));
noticeRepository.delete(noticeEntity);
}
@DeleteMapping("api/notice3/{id}")
public void chapter1_23(@PathVariable Long id) {
Notice noticeEntity = noticeRepository.findById(id)
.orElseThrow(() -> new NoticeNotFoundException("공지사항의 글이 존재하지 않습니다."));
if (noticeEntity.isDeleted()) {
throw new AlreadyDeletedException("이미 삭제된 게시글 입니다.");
}
noticeEntity
.setDeleted(true)
.setDeleteDate(LocalDateTime.now());
noticeRepository.save(noticeEntity);
}
@DeleteMapping("/api/notice4")
public void chapter1_24(@RequestBody NoticeDeleteInput noticeDeleteInput) {
List<Notice> noticeList = noticeRepository.findByIdIn(noticeDeleteInput.getIdList())
.orElseThrow(() -> new NoticeNotFoundException("공지사항의 글이 존재하지 않습니다."));
noticeList.forEach(notice -> {
notice
.setDeleted(true)
.setDeleteDate(LocalDateTime.now());
});
noticeRepository.saveAll(noticeList);
}
@DeleteMapping("/api/notice/all")
public void chapter1_25() {
noticeRepository.deleteAll();
}
@PostMapping("/api/notice6")
public ResponseEntity<String> chapter1_26(@RequestBody NoticeInput noticeInput) {
noticeRepository.save(Notice.builder()
.title(noticeInput.getTitle())
.contents(noticeInput.getContents())
.regDate(LocalDateTime.now())
.build());
return new ResponseEntity<>("CREATED", HttpStatus.CREATED);
}
@PostMapping("/api/notice7")
public ResponseEntity<?> chapter1_27(@RequestBody @Valid NoticeInput noticeInput,
BindingResult bindingResult) {
if (bindingResult.hasFieldErrors()) {
List<ResponseError> errors = new ArrayList<>();
bindingResult.getFieldErrors().forEach(e -> errors.add(ResponseError.of(e)));
return new ResponseEntity<>(errors, HttpStatus.BAD_REQUEST);
}
noticeRepository.save(Notice.builder()
.title(noticeInput.getTitle())
.contents(noticeInput.getContents())
.regDate(LocalDateTime.now())
.build());
return new ResponseEntity<>("CREATED", HttpStatus.CREATED);
}
@PostMapping("/api/notice8")
public ResponseEntity<?> chapter1_28(@RequestBody @Valid NoticeInput noticeInput,
BindingResult bindingResult) {
if (bindingResult.hasFieldErrors()) {
List<ResponseError> errors = new ArrayList<>();
bindingResult.getFieldErrors().forEach(e -> errors.add(ResponseError.of(e)));
return new ResponseEntity<>(errors, HttpStatus.BAD_REQUEST);
}
noticeRepository.save(Notice.builder()
.title(noticeInput.getTitle())
.contents(noticeInput.getContents())
.regDate(LocalDateTime.now())
.build());
return new ResponseEntity<>("CREATED", HttpStatus.CREATED);
}
@GetMapping("/api/notice/latest/{size}")
public Page<Notice> chapter1_29(@PathVariable int size) {
return noticeRepository.findAll(PageRequest.of(0, size, Sort.Direction.DESC, "regDate"));
}
@PostMapping("/api/notice9")
public ResponseEntity<?> chapter1_30(@RequestBody @Valid NoticeInput noticeInput,
BindingResult bindingResult) throws DuplicateNoticeException {
if (bindingResult.hasFieldErrors()) {
List<ResponseError> errors = new ArrayList<>();
bindingResult.getFieldErrors().forEach(e -> errors.add(ResponseError.of(e)));
return new ResponseEntity<>(errors, HttpStatus.BAD_REQUEST);
}
// 중복체크
// regDate > checkDate 이면 1분 미만
LocalDateTime checkDate = LocalDateTime.now().minusMinutes(1);
int noticeCount = noticeRepository.countByTitleAndContentsAndRegDateGreaterThanEqual(
noticeInput.getTitle(),
noticeInput.getContents(),
checkDate
);
if (noticeCount > 0 ) {
throw new DuplicateNoticeException("1분 이내에 등록된 공지사항이 존재합니다");
}
noticeRepository.save(Notice.builder()
.title(noticeInput.getTitle())
.contents(noticeInput.getContents())
.regDate(LocalDateTime.now())
.build());
return new ResponseEntity<>("CREATED", HttpStatus.CREATED);
}
}

View File

@@ -0,0 +1,57 @@
package com.example.restcontroller.notice.entity;
import com.example.restcontroller.user.entity.User;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import org.hibernate.annotations.ColumnDefault;
import javax.persistence.*;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Accessors(chain = true)
@Data
@Entity
public class Notice {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn
private User user;
@JsonIgnore
@OneToMany(mappedBy = "notice")
List<NoticeLike> noticeLikeList = new ArrayList<>();
private String title;
private String contents;
private LocalDateTime regDate;
private LocalDateTime updateDate;
private LocalDateTime deleteDate;
@ColumnDefault("false")
private boolean deleted;
@ColumnDefault("0")
private Integer hits;
@ColumnDefault("0")
private Integer likes;
@PrePersist
private void prePersist() {
hits = hits == null ? 0 : hits;
likes = likes == null ? 0 : likes;
}
}

View File

@@ -0,0 +1,34 @@
package com.example.restcontroller.notice.entity;
import com.example.restcontroller.user.entity.User;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import org.hibernate.annotations.ColumnDefault;
import javax.persistence.*;
import java.time.LocalDateTime;
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Accessors(chain = true)
@Data
@Entity
public class NoticeLike {
//ID, 제목, 내용, 등록일(작성일)
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn
private Notice notice;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn
private User user;
}

View File

@@ -0,0 +1,8 @@
package com.example.restcontroller.notice.exception;
public class AlreadyDeletedException extends RuntimeException {
public AlreadyDeletedException(String message) {
super(message);
}
}

View File

@@ -0,0 +1,8 @@
package com.example.restcontroller.notice.exception;
public class DuplicateNoticeException extends RuntimeException {
public DuplicateNoticeException(String message) {
super(message);
}
}

View File

@@ -0,0 +1,8 @@
package com.example.restcontroller.notice.exception;
public class NoticeNotFoundException extends RuntimeException{
public NoticeNotFoundException(String message) {
super(message);
}
}

View File

@@ -0,0 +1,11 @@
package com.example.restcontroller.notice.model;
import lombok.Data;
import java.util.List;
@Data
public class NoticeDeleteInput {
List<Long> idList;
}

View File

@@ -0,0 +1,25 @@
package com.example.restcontroller.notice.model;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.hibernate.validator.constraints.Length;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
@AllArgsConstructor
@NoArgsConstructor
@Data
@Builder
public class NoticeInput {
@NotBlank(message = "제목을 입력 해주세요")
@Size(min = 10, max = 50, message = "제목은 최소 10자 이상 최대 50자 입력 가능합니다.")
private String title;
@NotBlank(message = "내용을 입력 해주세요")
@Length(min =30, max = 1000, message = "내용은 최소 50자 이상 최대 1000자 입력 가능합니다.")
private String contents;
}

View File

@@ -0,0 +1,24 @@
package com.example.restcontroller.notice.model;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import java.time.LocalDateTime;
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Accessors(chain = true)
@Data
public class NoticeModel {
//ID, 제목, 내용, 등록일(작성일)
private Long id;
private String title;
private String contents;
private LocalDateTime regDate;
}

View File

@@ -0,0 +1,42 @@
package com.example.restcontroller.notice.model;
import com.example.restcontroller.notice.entity.Notice;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDateTime;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class NoticeResponse {
private Long id;
private Long regUserId;
private String regUserName;
private String title;
private String contents;
private LocalDateTime regDate;
private LocalDateTime updateDate;
private Integer hits;
private Integer likes;
public static NoticeResponse of(Notice notice) {
return NoticeResponse.builder()
.id(notice.getId())
.regUserId(notice.getUser().getId())
.regUserName(notice.getUser().getUserName())
.title(notice.getTitle())
.contents(notice.getContents())
.regDate(notice.getRegDate())
.updateDate(notice.getUpdateDate())
.hits(notice.getHits())
.likes(notice.getLikes())
.build();
}
}

View File

@@ -0,0 +1,32 @@
package com.example.restcontroller.notice.model;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.validation.FieldError;
import java.util.List;
import java.util.stream.Collectors;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ResponseError {
private String field;
private String message;
public static ResponseError of(FieldError e) {
return ResponseError.builder()
.field(e.getField())
.message(e.getDefaultMessage())
.build();
}
public static List<ResponseError> of(List<FieldError> fieldErrors) {
return fieldErrors.stream()
.map(ResponseError::of)
.collect(Collectors.toList());
}
}

View File

@@ -0,0 +1,15 @@
package com.example.restcontroller.notice.repository;
import com.example.restcontroller.notice.entity.NoticeLike;
import com.example.restcontroller.user.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
import java.util.Optional;
@Repository
public interface NoticeLikeRepository extends JpaRepository<NoticeLike, Long> {
List<NoticeLike> findByUser(User user);
}

View File

@@ -0,0 +1,25 @@
package com.example.restcontroller.notice.repository;
import com.example.restcontroller.notice.entity.Notice;
import com.example.restcontroller.user.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
@Repository
public interface NoticeRepository extends JpaRepository<Notice, Long> {
Optional<List<Notice>> findByIdIn(List<Long> idList);
// 제목동일, 내용동일, 등록시간이 체크시간보다 크다.
Optional<List<Notice>> findByTitleAndContentsAndRegDateIsGreaterThanEqual(String title, String contents, LocalDateTime regDate);
int countByTitleAndContentsAndRegDateGreaterThanEqual(String title, String contents, LocalDateTime regDate);
Optional<List<Notice>> findByUser(User user);
int countByUser(User user);
}

View File

@@ -0,0 +1,141 @@
package com.example.restcontroller.user.controller;
import com.example.restcontroller.notice.repository.NoticeRepository;
import com.example.restcontroller.user.entity.User;
import com.example.restcontroller.user.exception.UserNotFoundException;
import com.example.restcontroller.user.model.*;
import com.example.restcontroller.user.repository.UserLoginHistoryRepository;
import com.example.restcontroller.user.repository.UserRepository;
import com.example.restcontroller.user.service.UserService;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Optional;
@RestController
@RequiredArgsConstructor
public class ApiAdminUserController {
private final UserRepository userRepository;
private final NoticeRepository noticeRepository;
private final UserLoginHistoryRepository userLoginHistoryRepository;
private final UserService userService;
@GetMapping("/api/admin/user")
public ResponseEntity<?> chapter2_18() {
UserCount userCount = UserCount.builder()
.totalCount(userRepository.count())
.data(userRepository.findAll())
.build();
return ResponseEntity.ok(userCount);
}
@GetMapping("/api/admin/user/{id}")
public ResponseEntity<?> chapter2_19(@PathVariable Long id) {
Optional<User> userEntity = userRepository.findById(id);
if (userEntity.isEmpty()) {
return ResponseEntity.badRequest().body(ResponseMessage.fail("사용자 정보가 존재하지 않습니다."));
}
return ResponseEntity.ok().body(ResponseMessage.success(userEntity.get()));
}
@GetMapping("/api/admin/user/search")
public ResponseEntity<?> chapter2_20(@RequestBody UserSearch userSearch) {
List<User> userList = userRepository.findByEmailContainsAndUserNameContainsAndPhoneContains(
userSearch.getEmail(), userSearch.getUserName(), userSearch.getPhone()
);
return ResponseEntity.ok().body(ResponseMessage.success(userList));
}
@PatchMapping("/api/admin/user/{id}/status")
public ResponseEntity<?> chapter2_21(@PathVariable Long id) {
User userEntity = userRepository.findById(id)
.orElseThrow(() -> new UserNotFoundException("유저가 없습니다."));
String userStatus = userEntity.changeUserStatus();
userRepository.save(userEntity);
return ResponseEntity.ok().body(userStatus);
}
@DeleteMapping("/api/admin/user/{id}")
public ResponseEntity<?> chapter2_22(@PathVariable Long id) {
User userEntity = userRepository.findById(id)
.orElseThrow(() -> new UserNotFoundException("유저가 없습니다."));
if (noticeRepository.countByUser(userEntity) > 0) {
return new ResponseEntity<>(ResponseMessage.fail("사용자가 작성한 공지사항이 있습니다."), HttpStatus.BAD_REQUEST);
}
userRepository.deleteById(id);
return ResponseEntity.ok().build();
}
@GetMapping("/api/admin/user/login/history")
public ResponseEntity<?> chapter2_23() {
return ResponseEntity.ok().body(ResponseMessage.success(userLoginHistoryRepository.findAll()));
}
@PatchMapping("/api/admin/user/{id}/lock")
public ResponseEntity<?> chapter2_24(@PathVariable Long id) {
User userEntity = userRepository.findById(id)
.orElseThrow(() -> new UserNotFoundException("유저가 없습니다."));
if (userEntity.isLockYn()) {
return ResponseEntity.badRequest().body(ResponseMessage.fail("이미 접속제한이 된 사용자 입니다."));
}
userEntity.setLockYn(true);
userRepository.save(userEntity);
return ResponseEntity.ok().body(ResponseMessage.success());
}
@PatchMapping("/api/admin/user/{id}/unlock")
public ResponseEntity<?> chapter2_25(@PathVariable Long id) {
User userEntity = userRepository.findById(id)
.orElseThrow(() -> new UserNotFoundException("유저가 없습니다."));
if (!userEntity.isLockYn()) {
return ResponseEntity.badRequest().body(ResponseMessage.fail("접속 가능한 사용자 입니다."));
}
userEntity.setLockYn(false);
userRepository.save(userEntity);
return ResponseEntity.ok().body(ResponseMessage.success());
}
@GetMapping("/api/admin/user/status/count")
public ResponseEntity<?> chapter2_26() {
UserSummary userSummary = userService.getUserStatusCount();
return ResponseEntity.ok().body(ResponseMessage.success(userSummary));
}
@GetMapping("/api/admin/user/today")
public ResponseEntity<?> chapter2_27() {
List<UserResponse> todayUsers = userService.getTodayUsers();
return ResponseEntity.ok().body(ResponseMessage.success(todayUsers));
}
@GetMapping("/api/admin/user/notice/count")
public ResponseEntity<?> chapter2_28() {
List<UserNoticeCount> userNoticeCountList = userService.getUserNoticeCount();
return ResponseEntity.ok().body(ResponseMessage.success(userNoticeCountList));
}
@GetMapping("/api/admin/user/log/count")
public ResponseEntity<?> chapter2_29() {
List<UserLogCount> userLogCountList = userService.getUserLogCount();
return ResponseEntity.ok().body(ResponseMessage.success(userLogCountList));
}
@GetMapping("/api/admin/user/like/best")
public ResponseEntity<?> chapter2_30() {
List<UserLogCount> userLogCountList = userService.getUserLikeBest();
return ResponseEntity.ok().body(ResponseMessage.success(userLogCountList));
}
}

View File

@@ -0,0 +1,355 @@
package com.example.restcontroller.user.controller;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.SignatureVerificationException;
import com.example.restcontroller.notice.entity.Notice;
import com.example.restcontroller.notice.entity.NoticeLike;
import com.example.restcontroller.notice.exception.NoticeNotFoundException;
import com.example.restcontroller.notice.model.NoticeResponse;
import com.example.restcontroller.notice.model.ResponseError;
import com.example.restcontroller.notice.repository.NoticeLikeRepository;
import com.example.restcontroller.notice.repository.NoticeRepository;
import com.example.restcontroller.user.entity.User;
import com.example.restcontroller.user.exception.ExistsEmailException;
import com.example.restcontroller.user.exception.PasswordNotMatchException;
import com.example.restcontroller.user.exception.UserNotFoundException;
import com.example.restcontroller.user.model.*;
import com.example.restcontroller.user.repository.UserRepository;
import com.example.restcontroller.util.JWTUtils;
import com.example.restcontroller.util.PasswordUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
@RestController
@RequiredArgsConstructor
public class ApiUserController {
private final UserRepository userRepository;
private final NoticeRepository noticeRepository;
private final NoticeLikeRepository noticeLikeRepository;
@PostMapping("/api/user")
public ResponseEntity<?> chapter2_1(@RequestBody @Valid UserInput userInput, BindingResult bindingResult) {
if (bindingResult.hasFieldErrors()) {
List<ResponseError> errors = bindingResult.getFieldErrors().stream()
.map(ResponseError::of)
.collect(Collectors.toList());
return new ResponseEntity<>(errors, HttpStatus.BAD_REQUEST);
}
return new ResponseEntity<>(HttpStatus.CREATED);
}
@PostMapping("/api/user2")
public ResponseEntity<?> chapter2_2(@RequestBody @Valid UserInput userInput, BindingResult bindingResult) {
if (bindingResult.hasFieldErrors()) {
List<ResponseError> errors = bindingResult.getFieldErrors().stream()
.map(ResponseError::of)
.collect(Collectors.toList());
return new ResponseEntity<>(errors, HttpStatus.BAD_REQUEST);
}
userRepository.save(new User(userInput));
return new ResponseEntity<>(HttpStatus.CREATED);
}
@PutMapping("/api/user/{id}")
public ResponseEntity<?> chapter2_3(@PathVariable Long id, @RequestBody @Valid UserUpdate userUpdate, BindingResult bindingResult) {
if (bindingResult.hasFieldErrors()) {
List<ResponseError> errors = bindingResult.getFieldErrors().stream()
.map(ResponseError::of)
.collect(Collectors.toList());
return new ResponseEntity<>(errors, HttpStatus.BAD_REQUEST);
}
User userEntity = userRepository.findById(id)
.orElseThrow(() -> new UserNotFoundException("사용자 정보가 없습니다."));
User user = User.updateUser(userEntity, userUpdate.getPhone());
userRepository.save(user);
return new ResponseEntity<>(HttpStatus.OK);
}
@GetMapping("/api/user/{id}")
public ResponseEntity<?> chapter2_4(@PathVariable Long id) {
User userEntity = userRepository.findById(id)
.orElseThrow(() -> new UserNotFoundException("사용자 정보가 없습니다."));
// UserResponse response = new UserResponse(userEntity);
UserResponse response = UserResponse.of(userEntity);
return new ResponseEntity<>(response, HttpStatus.OK);
}
@GetMapping("/api/user/{id}/notice")
public List<NoticeResponse> chapter2_5(@PathVariable Long id) {
User userEntity = userRepository.findById(id)
.orElseThrow(() -> new UserNotFoundException("사용자 정보가 없습니다."));
List<Notice> noticeList = noticeRepository.findByUser(userEntity)
.orElseThrow(() -> new NoticeNotFoundException("공지사항이 없습니다."));
return noticeList.stream().map(NoticeResponse::of).collect(Collectors.toList());
}
@PostMapping("/api/user3")
public ResponseEntity<?> chapter2_6(@RequestBody @Valid UserInput userInput, BindingResult bindingResult) {
if (bindingResult.hasFieldErrors()) {
List<ResponseError> errors = bindingResult.getFieldErrors().stream()
.map(ResponseError::of)
.collect(Collectors.toList());
return new ResponseEntity<>(errors, HttpStatus.BAD_REQUEST);
}
if (userRepository.countByEmail(userInput.getEmail()) > 0) {
throw new ExistsEmailException("이미 존재하는 이메일 입니다.");
}
userRepository.save(new User(userInput));
return new ResponseEntity<>(HttpStatus.CREATED);
}
@PatchMapping("/api/user/{id}/password")
public ResponseEntity<?> chapter2_7(@PathVariable Long id, @RequestBody UserPasswordUpdate userPasswordUpdate, BindingResult bindingResult) {
if (bindingResult.hasFieldErrors()) {
List<ResponseError> errors = bindingResult.getFieldErrors().stream()
.map(ResponseError::of)
.collect(Collectors.toList());
return new ResponseEntity<>(errors, HttpStatus.BAD_REQUEST);
}
User userEntity = userRepository.findByIdAndPassword(id, userPasswordUpdate.getPassword())
.orElseThrow(() -> new PasswordNotMatchException("비밀번호가 일치하지 않습니다."));
userEntity.setPassword(userPasswordUpdate.getNewPassword());
userRepository.save(userEntity);
return new ResponseEntity<>(HttpStatus.OK);
}
private String getEncryptPassword(String password) {
BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
return passwordEncoder.encode(password);
}
@PostMapping("/api/user4")
public ResponseEntity<?> chapter2_8(@RequestBody @Valid UserInput userInput, BindingResult bindingResult) {
if (bindingResult.hasFieldErrors()) {
List<ResponseError> errors = bindingResult.getFieldErrors().stream()
.map(ResponseError::of)
.collect(Collectors.toList());
return new ResponseEntity<>(errors, HttpStatus.BAD_REQUEST);
}
userRepository.save(User.builder()
.email(userInput.getEmail())
.userName(userInput.getUserName())
.password(getEncryptPassword(userInput.getPassword()))
.phone(userInput.getPhone())
.regDate(LocalDateTime.now())
.build());
return new ResponseEntity<>(HttpStatus.CREATED);
}
@DeleteMapping("/api/user/{id}")
public ResponseEntity<?> chapter2_9(@PathVariable Long id) {
User userEntity = userRepository.findById(id)
.orElseThrow(() -> new UserNotFoundException("사용자가 없습니다."));
userRepository.deleteById(id);
return new ResponseEntity<>(HttpStatus.OK);
}
@GetMapping("/api/user")
public ResponseEntity<?> chapter2_10(@Valid FindUserId findUserId, BindingResult bindingResult) {
if (bindingResult.hasFieldErrors()) {
List<ResponseError> errors = bindingResult.getFieldErrors().stream()
.map(ResponseError::of)
.collect(Collectors.toList());
return new ResponseEntity<>(errors, HttpStatus.BAD_REQUEST);
}
User userEntity = userRepository.findByUserNameAndPhone(findUserId.getUserName(), findUserId.getPhone())
.orElseThrow(() -> new UserNotFoundException("사용자가 없습니다."));
return new ResponseEntity<>(userEntity.getEmail(), HttpStatus.OK);
}
private String getResetPassword() {
return UUID.randomUUID().toString().replaceAll("-", "").substring(0, 10);
}
void sendSMS(String message) {
System.out.println("문자메시지 전송 : " + message);
}
@GetMapping("/api/user/{id}/password/reset")
public ResponseEntity<?> chapter2_11(@PathVariable Long id) {
User userEntity = userRepository.findById(id)
.orElseThrow(() -> new UserNotFoundException("사용자가 없습니다."));
String temp = getResetPassword();
userEntity.setPassword(getEncryptPassword(temp));
userRepository.save(userEntity);
String message = String.format("[%s]님의 임시비밀번호가 [%s]로 초기화 되었습니다.",
userEntity.getUserName(),
temp);
sendSMS(message);
return ResponseEntity.ok().build();
}
@GetMapping("/api/user/{id}/notice/like")
public ResponseEntity<?> chapter2_12(@PathVariable Long id) {
User userEntity = userRepository.findById(id)
.orElseThrow(() -> new UserNotFoundException("사용자가 없습니다."));
List<NoticeLike> noticeLikeList = noticeLikeRepository.findByUser(userEntity);
return ResponseEntity.ok().body(noticeLikeList);
}
@PostMapping("/api/user/login")
public ResponseEntity<?> chapter2_13(@RequestBody @Valid UserLogin userLogin, BindingResult bindingResult) {
if (bindingResult.hasFieldErrors()) {
List<ResponseError> errors = bindingResult.getFieldErrors().stream()
.map(ResponseError::of)
.collect(Collectors.toList());
return new ResponseEntity<>(errors, HttpStatus.BAD_REQUEST);
}
User userEntity = userRepository.findByEmail(userLogin.getEmail())
.orElseThrow(() -> new UserNotFoundException("사용자가 없습니다."));
if (!PasswordUtils.equalPassword(userLogin.getPassword(), userEntity.getPassword())) {
throw new PasswordNotMatchException("비밀번호가 일치하지 않습니다.");
}
return ResponseEntity.ok().build();
}
@PostMapping("/api/user/login2")
public ResponseEntity<?> chapter2_14(@RequestBody @Valid UserLogin userLogin, BindingResult bindingResult) {
if (bindingResult.hasFieldErrors()) {
List<ResponseError> errors = bindingResult.getFieldErrors().stream()
.map(ResponseError::of)
.collect(Collectors.toList());
return new ResponseEntity<>(errors, HttpStatus.BAD_REQUEST);
}
User userEntity = userRepository.findByEmail(userLogin.getEmail())
.orElseThrow(() -> new UserNotFoundException("사용자가 없습니다."));
if (!PasswordUtils.equalPassword(userLogin.getPassword(), userEntity.getPassword())) {
throw new PasswordNotMatchException("비밀번호가 일치하지 않습니다.");
}
String token = JWT.create()
.withExpiresAt(new Date())
.withClaim("user_id", userEntity.getId())
.withSubject(userEntity.getEmail())
.withIssuer(userEntity.getEmail())
.sign(Algorithm.HMAC512("kim".getBytes()));
return ResponseEntity.ok().body(UserLoginToken.builder().token(token).build());
}
@PostMapping("/api/user/login3")
public ResponseEntity<?> chapter2_15(@RequestBody @Valid UserLogin userLogin, BindingResult bindingResult) {
if (bindingResult.hasFieldErrors()) {
List<ResponseError> errors = bindingResult.getFieldErrors().stream()
.map(ResponseError::of)
.collect(Collectors.toList());
return new ResponseEntity<>(errors, HttpStatus.BAD_REQUEST);
}
User userEntity = userRepository.findByEmail(userLogin.getEmail())
.orElseThrow(() -> new UserNotFoundException("사용자가 없습니다."));
if (!PasswordUtils.equalPassword(userLogin.getPassword(), userEntity.getPassword())) {
throw new PasswordNotMatchException("비밀번호가 일치하지 않습니다.");
}
String token = JWT.create()
.withExpiresAt(Timestamp.valueOf(LocalDateTime.now().plusMinutes(30)))
.withClaim("user_id", userEntity.getId())
.withSubject(userEntity.getEmail())
.withIssuer(userEntity.getEmail())
.sign(Algorithm.HMAC512("kim".getBytes()));
return ResponseEntity.ok().body(UserLoginToken.builder().token(token).build());
}
@PatchMapping("/api/user/login")
public ResponseEntity<?> chapter2_16(HttpServletRequest request) {
String token = request.getHeader("TOKEN");
String email;
try {
email = JWT.require(Algorithm.HMAC512("kim".getBytes()))
.build()
.verify(token)
.getIssuer();
} catch (SignatureVerificationException e) {
throw new PasswordNotMatchException("유효한 토큰이 아닙니다.");
}
User userEntity = userRepository.findByEmail(email)
.orElseThrow(() -> new UserNotFoundException("사용자 정보 없음"));
String newToken = JWT.create()
.withExpiresAt(Timestamp.valueOf(LocalDateTime.now().plusMinutes(30)))
.withClaim("user_id", userEntity.getId())
.withSubject(userEntity.getEmail())
.withIssuer(userEntity.getEmail())
.sign(Algorithm.HMAC512("kim".getBytes()));
return ResponseEntity.ok().body(UserLoginToken.builder().token(newToken).build());
}
@DeleteMapping("/api/user/login")
public ResponseEntity<?> chapter2_17(@RequestHeader("TOKEN") String token) {
try {
String email = JWTUtils.getIssuer(token);
} catch (SignatureVerificationException e) {
return new ResponseEntity<>("토큰이 유효하지 않습니다.", HttpStatus.BAD_REQUEST);
}
// 세션, 쿠키삭제
// 클라이언트 쿠키/로컬스토리지/세션스토리지
// 블랙리스트 작성
// ...
return ResponseEntity.ok().build();
}
}

View File

@@ -0,0 +1,94 @@
package com.example.restcontroller.user.entity;
import com.example.restcontroller.board.entity.Board;
import com.example.restcontroller.board.entity.BoardHits;
import com.example.restcontroller.board.entity.BoardLike;
import com.example.restcontroller.board.entity.BoardType;
import com.example.restcontroller.notice.entity.Notice;
import com.example.restcontroller.notice.entity.NoticeLike;
import com.example.restcontroller.user.model.UserInput;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.*;
import javax.persistence.*;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
@Getter @Setter
@AllArgsConstructor
@NoArgsConstructor
@Builder
@Entity
public class User {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(unique = true, nullable = false)
private String email;
@Column(nullable = false)
private String userName;
@Column(nullable = false)
private String password;
@Column(nullable = false)
private String phone;
@Enumerated(EnumType.STRING)
private UserStatus status;
@Column
private boolean lockYn;
private LocalDateTime regDate;
private LocalDateTime updateDate;
@JsonIgnore
@OneToMany(mappedBy = "user")
List<Notice> noticeList = new ArrayList<>();
@JsonIgnore
@OneToMany(mappedBy = "user")
List<NoticeLike> noticeLikeList = new ArrayList<>();
@JsonIgnore
@OneToMany(mappedBy = "user")
List<Board> boardList = new ArrayList<>();
@JsonIgnore
@OneToMany(mappedBy = "user")
List<BoardHits> boardHitsList = new ArrayList<>();
@JsonIgnore
@OneToMany(mappedBy = "user")
List<BoardLike> boardLikeList = new ArrayList<>();
@PrePersist
public void prePersist() {
status = status == null ? UserStatus.USING : status;
}
public User(UserInput userInput) {
email = userInput.getEmail();
userName = userInput.getUserName();
password = userInput.getPassword();
phone = userInput.getPhone();
regDate = LocalDateTime.now();
}
public static User updateUser(User user, String phone) {
user.phone = phone;
user.updateDate = LocalDateTime.now();
return user;
}
public String changeUserStatus() {
status = status.equals(UserStatus.USING) ? UserStatus.STOP : UserStatus.USING;
return status.toString();
}
}

View File

@@ -0,0 +1,35 @@
package com.example.restcontroller.user.entity;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.*;
import java.time.LocalDateTime;
@Entity
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class UserLoginHistory {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column
private Long userId;
@Column
private String email;
@Column
private String userName;
@Column
private LocalDateTime loginDate;
@Column
private String ipAddr;
}

View File

@@ -0,0 +1,14 @@
package com.example.restcontroller.user.entity;
public enum UserStatus {
NONE, USING, STOP;
int value;
UserStatus() {
}
public int getValue() {
return this.value;
}
}

View File

@@ -0,0 +1,7 @@
package com.example.restcontroller.user.exception;
public class ExistsEmailException extends RuntimeException {
public ExistsEmailException(String s) {
super(s);
}
}

View File

@@ -0,0 +1,7 @@
package com.example.restcontroller.user.exception;
public class PasswordNotMatchException extends RuntimeException {
public PasswordNotMatchException(String message) {
super(message);
}
}

View File

@@ -0,0 +1,8 @@
package com.example.restcontroller.user.exception;
public class UserNotFoundException extends RuntimeException{
public UserNotFoundException(String message) {
super(message);
}
}

View File

@@ -0,0 +1,24 @@
package com.example.restcontroller.user.model;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
@AllArgsConstructor
@NoArgsConstructor
@Data
@Builder
public class FindUserId {
@NotBlank(message = "이름은 필수 항목 입니다.")
private String userName;
@NotBlank(message = "연락처는 필수 항목 입니다.")
@Size(max = 20, message = "연락처는 최대 20자까지 입력해야 합니다.")
private String phone;
}

View File

@@ -0,0 +1,50 @@
package com.example.restcontroller.user.model;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.http.HttpStatus;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class ResponseMessage<T> {
private ResponseMessageHeader header;
private T body;
public static <T> ResponseMessage<?> fail(String message, T data) {
return ResponseMessage.builder()
.header(ResponseMessageHeader.builder()
.result(false)
.resultCode(HttpStatus.BAD_REQUEST.value())
.message(message)
.status(HttpStatus.BAD_REQUEST)
.build())
.body(data)
.build();
}
public static ResponseMessage<?> fail(String message) {
return fail(message, null);
}
public static <T> ResponseMessage<?> success(T data) {
return ResponseMessage.builder()
.header(ResponseMessageHeader.builder()
.result(true)
.resultCode(HttpStatus.OK.value())
.message("")
.status(HttpStatus.OK)
.build())
.body(data)
.build();
}
public static ResponseMessage<?> success() {
return success(null);
}
}

View File

@@ -0,0 +1,20 @@
package com.example.restcontroller.user.model;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.http.HttpStatus;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class ResponseMessageHeader {
private boolean result;
private int resultCode;
private String message;
private HttpStatus status;
}

View File

@@ -0,0 +1,20 @@
package com.example.restcontroller.user.model;
import com.example.restcontroller.user.entity.User;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class UserCount {
private Long totalCount;
private List<User> data;
}

View File

@@ -0,0 +1,31 @@
package com.example.restcontroller.user.model;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserInput {
@NotBlank(message = "이메일은 필수 항목 입니다.")
@Email(message = "이메일 형식에 맞게 입력해 주세요.")
private String email;
@NotBlank(message = "이름은 필수 항목 입니다.")
private String userName;
@NotBlank(message = "비밀번호는 필수 항목 입니다.")
@Size(min = 4, message = "비밀번호는 4자 이상 입력해야 합니다.")
private String password;
@NotBlank(message = "연락처는 필수 항목 입니다.")
@Size(max = 20, message = "연락처는 최대 20자까지 입력해야 합니다.")
private String phone;
}

View File

@@ -0,0 +1,20 @@
package com.example.restcontroller.user.model;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class UserLogCount {
private Long id;
private String email;
private String userName;
private Long noticeCount;
private Long noticeLikeCount;
}

View File

@@ -0,0 +1,21 @@
package com.example.restcontroller.user.model;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.NotBlank;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class UserLogin {
@NotBlank(message = "이메일 항목은 필수 입니다.")
private String email;
@NotBlank(message = "비밀번호 항목은 필수 입니다.")
private String password;
}

View File

@@ -0,0 +1,15 @@
package com.example.restcontroller.user.model;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class UserLoginToken {
private String token;
}

View File

@@ -0,0 +1,29 @@
package com.example.restcontroller.user.model;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class UserNoticeCount {
private Long id;
private String email;
private String userName;
private Long noticeCount;
public static UserNoticeCount of(Object[] data) {
return UserNoticeCount.builder()
.id((Long) data[0])
.email((String) data[1])
.userName((String) data[2])
.noticeCount((Long) data[3])
.build();
}
}

View File

@@ -0,0 +1,23 @@
package com.example.restcontroller.user.model;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class UserPasswordUpdate {
@NotBlank(message = "비밀번호를 입력하세요.")
private String password;
@Size(min = 4, max = 20, message = "비밀번호는 4-20 사이의 길이로 입력해 주세요.")
@NotBlank(message = "비밀번호를 입력하세요.")
private String newPassword;
}

View File

@@ -0,0 +1,33 @@
package com.example.restcontroller.user.model;
import com.example.restcontroller.user.entity.User;
import lombok.*;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class UserResponse {
private Long id;
private String email;
private String userName;
private String phone;
public UserResponse(User user) {
this.id = user.getId();
this.email = user.getEmail();
this.userName = user.getUserName();
this.phone = user.getPhone();
}
public static UserResponse of(User user) {
return UserResponse.builder()
.id(user.getId())
.email(user.getEmail())
.userName(user.getUserName())
.phone(user.getPhone())
.build();
}
}

View File

@@ -0,0 +1,17 @@
package com.example.restcontroller.user.model;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class UserSearch {
private String email;
private String userName;
private String phone;
}

View File

@@ -0,0 +1,17 @@
package com.example.restcontroller.user.model;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class UserSummary {
private Long totalUserCount;
private Long usingUserCount;
private Long stopUserCount;
}

View File

@@ -0,0 +1,20 @@
package com.example.restcontroller.user.model;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class UserUpdate {
@Size(max = 20, message = "연락처는 최대 20자 까지 입력해야 합니다.")
@NotBlank(message = "연락처는 필수 항목 입니다.")
private String phone;
}

View File

@@ -0,0 +1,40 @@
package com.example.restcontroller.user.repository;
import com.example.restcontroller.user.model.UserNoticeCount;
import com.example.restcontroller.user.model.UserLogCount;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Repository;
import javax.persistence.EntityManager;
import java.util.List;
@Repository
@RequiredArgsConstructor
public class UserCustomRepository {
private final EntityManager entityManager;
public List<UserNoticeCount> findUserNoticeCount() {
String sql = "select u.id, u.email, u.user_name, (select count(*) from Notice n where n.user_id = u.id) notice_count from User u ";
List<UserNoticeCount> list = entityManager.createNativeQuery(sql).getResultList();
return list;
}
public List<UserLogCount> findUserLogCount() {
String sql = "select u.id, u.email, u.user_name" +
", (select count(*) from notice n where n.user_id = u.id) notice_count" +
", (select count(*) from notice_like nl where nl.user_id = u.id) notice_like_count" +
" from user u ";
List<UserLogCount> list = entityManager.createNativeQuery(sql).getResultList();
return list;
}
public List<UserLogCount> findUserLikeBest() {
String sql = "select u.id, u.email, u.user_name" +
", (select count(*) from notice_like nl where nl.user_id = u.id) notice_like_count" +
" from user u " +
" order by notice_like_count desc";
List<UserLogCount> list = entityManager.createNativeQuery(sql).getResultList();
return list;
}
}

View File

@@ -0,0 +1,9 @@
package com.example.restcontroller.user.repository;
import com.example.restcontroller.user.entity.UserLoginHistory;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface UserLoginHistoryRepository extends JpaRepository<UserLoginHistory, Long> {
}

View File

@@ -0,0 +1,33 @@
package com.example.restcontroller.user.repository;
import com.example.restcontroller.user.entity.User;
import com.example.restcontroller.user.entity.UserStatus;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
int countByEmail(String email);
Optional<User> findByIdAndPassword(Long id, String password);
Optional<User> findByUserNameAndPhone(String userName, String phone);
Optional<User> findByEmail(String email);
List<User> findByEmailContainsAndUserNameContainsAndPhoneContains(String email, String userName, String phone);
Long countByStatus(UserStatus userStatus);
List<User> findByRegDateBetween(LocalDateTime startDate, LocalDateTime endDate);
@Query("select u from User u where u.regDate between :startDate and :endDate")
List<User> findTodayUsers(LocalDateTime startDate, LocalDateTime endDate);
}

View File

@@ -0,0 +1,21 @@
package com.example.restcontroller.user.service;
import com.example.restcontroller.user.model.UserNoticeCount;
import com.example.restcontroller.user.model.UserLogCount;
import com.example.restcontroller.user.model.UserResponse;
import com.example.restcontroller.user.model.UserSummary;
import java.util.List;
public interface UserService {
UserSummary getUserStatusCount();
List<UserResponse> getTodayUsers();
List<UserNoticeCount> getUserNoticeCount();
List<UserLogCount> getUserLogCount();
List<UserLogCount> getUserLikeBest();
}

View File

@@ -0,0 +1,65 @@
package com.example.restcontroller.user.service;
import com.example.restcontroller.user.entity.UserStatus;
import com.example.restcontroller.user.model.UserNoticeCount;
import com.example.restcontroller.user.model.UserLogCount;
import com.example.restcontroller.user.model.UserResponse;
import com.example.restcontroller.user.model.UserSummary;
import com.example.restcontroller.user.repository.UserCustomRepository;
import com.example.restcontroller.user.repository.UserRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.List;
import java.util.stream.Collectors;
@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class UserServiceImpl implements UserService {
private final UserRepository userRepository;
private final UserCustomRepository userCustomRepository;
@Override
public UserSummary getUserStatusCount() {
Long usingUserCount = userRepository.countByStatus(UserStatus.USING);
Long stopUserCount = userRepository.countByStatus(UserStatus.STOP);
Long totalUserCount = userRepository.count();
return UserSummary.builder()
.stopUserCount(stopUserCount)
.usingUserCount(usingUserCount)
.totalUserCount(totalUserCount)
.build();
}
@Override
public List<UserResponse> getTodayUsers() {
LocalDateTime startDate = LocalDateTime.of(LocalDate.now(), LocalTime.of(0, 0));
LocalDateTime endDate = startDate.plusDays(1);
return userRepository.findTodayUsers(startDate, endDate)
.stream().map(UserResponse::of).collect(Collectors.toList());
}
@Override
public List<UserNoticeCount> getUserNoticeCount() {
return userCustomRepository.findUserNoticeCount();
}
@Override
public List<UserLogCount> getUserLogCount() {
return userCustomRepository.findUserLogCount();
}
@Override
public List<UserLogCount> getUserLikeBest() {
return userCustomRepository.findUserLikeBest();
}
}

View File

@@ -0,0 +1,21 @@
package com.example.restcontroller.util;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.SignatureVerificationException;
import com.example.restcontroller.user.exception.PasswordNotMatchException;
import lombok.experimental.UtilityClass;
import org.springframework.security.crypto.bcrypt.BCrypt;
@UtilityClass
public class JWTUtils {
private final String KEY = "kim";
public static String getIssuer(String token) {
return JWT.require(Algorithm.HMAC512(KEY.getBytes()))
.build()
.verify(token)
.getIssuer();
}
}

View File

@@ -0,0 +1,12 @@
package com.example.restcontroller.util;
import lombok.experimental.UtilityClass;
import org.springframework.security.crypto.bcrypt.BCrypt;
@UtilityClass
public class PasswordUtils {
public static boolean equalPassword(String password, String encryptedPassword) {
return BCrypt.checkpw(password, encryptedPassword);
}
}

View File

@@ -0,0 +1,39 @@
spring:
h2:
console:
enabled: true
path: /h2-console
datasource:
url: jdbc:h2:mem:testDb
#url: jdbc:h2:file:/Users/parkkyutae/Documents/sources/github/fastcampus-demo-01/record-example/sample1/backofficeDb
driver-class-name: org.h2.Driver
username: sa
password:
jpa:
hibernate:
ddl-auto: create-drop
generate-ddl: true
properties:
hibernate:
format_sql: true
show-sql: true
jackson:
serialization:
fail-on-empty-beans: false
mvc:
hiddenmethod:
filter:
enabled: true
mustache:
suffix: .html
logging:
level:
org.hibernate.SQL: trace
org.hibernate.type: trace

View File

@@ -0,0 +1,51 @@
insert into user(email, password, phone, reg_date, user_name, status, lock_yn)
values
('test11@naver.com', '$2a$10$2ElPbt2mwiAc9IYH3rgJz.YZInXlUd363utdyU0TWfne6Y3vKh8h6', '010-1234-1234', '2021-02-20 00:50:11.000000', 'kim', 'USING', 0),
('test22@gmail.com', '$2a$10$2ElPbt2mwiAc9IYH3rgJz.YZInXlUd363utdyU0TWfne6Y3vKh8h6', '010-4321-1111', '2021-02-25 12:33:16.000000', 'lee', 'USING', 0),
('test33@naver.com', '$2a$10$2ElPbt2mwiAc9IYH3rgJz.YZInXlUd363utdyU0TWfne6Y3vKh8h6', '010-5555-3333', now(), 'hong', 'USING', 0),
('test44@gmail.com', '$2a$10$2ElPbt2mwiAc9IYH3rgJz.YZInXlUd363utdyU0TWfne6Y3vKh8h6', '010-4343-2546', now(), 'park', 'STOP', 0);
insert into notice(contents, reg_date, title, user_id)
values
('내용1', now(), '제목1', 1),
('내용2', now(), '제목2', 1),
('내용3', now(), '제목3', 1),
('내용4', now(), '제목4', 2),
('내용5', now(), '제목5', 2),
('내용6', now(), '제목6', 3),
('내용7', now(), '제목7', 3),
('내용8', now(), '제목8', 3),
('내용9', now(), '제목9', 3);
insert into notice_like(notice_id, user_id)
values
(1, 1),
(1, 2),
(2, 1),
(2, 2),
(2, 3),
(3, 1),
(4, 1),
(4, 2),
(5, 2),
(6, 4),
(7, 1),
(7, 4);
insert into board_type (board_name, reg_date, using_yn)
values
('게시판1', now(), 1),
('게시판2', now(), 0),
('게시판3', now(), 1);
insert into board (board_type_id, user_id, title, content, reg_date, top_yn)
values
(1, 1, '게시글1', '게시글 내용1', now(), 0),
(1, 2, '게시글2', '게시글 내용2', now(), 0),
(1, 3, '게시글3', '게시글 내용3', now(), 0),
(2, 1, '게시글4', '게시글 내용4', now(), 0),
(2, 2, '게시글5', '게시글 내용5', now(), 0),
(3, 1, '게시글6', '게시글 내용6', now(), 0),
(3, 3, '게시글7', '게시글 내용7', now(), 0);

View File

@@ -0,0 +1,13 @@
package com.example.restcontroller;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
class RestControllerApplicationTests {
@Test
void contextLoads() {
}
}