rest controller practice
This commit is contained in:
37
rest-controller-practice/.gitignore
vendored
Normal file
37
rest-controller-practice/.gitignore
vendored
Normal 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/
|
||||
58
rest-controller-practice/build.gradle
Normal file
58
rest-controller-practice/build.gradle
Normal 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
|
||||
}
|
||||
BIN
rest-controller-practice/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
BIN
rest-controller-practice/gradle/wrapper/gradle-wrapper.jar
vendored
Normal file
Binary file not shown.
5
rest-controller-practice/gradle/wrapper/gradle-wrapper.properties
vendored
Normal file
5
rest-controller-practice/gradle/wrapper/gradle-wrapper.properties
vendored
Normal 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
184
rest-controller-practice/gradlew
vendored
Normal 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
89
rest-controller-practice/gradlew.bat
vendored
Normal 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
|
||||
1
rest-controller-practice/settings.gradle
Normal file
1
rest-controller-practice/settings.gradle
Normal file
@@ -0,0 +1 @@
|
||||
rootProject.name = 'rest-controller'
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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<>();
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.example.restcontroller.board.exception;
|
||||
|
||||
public class BoardTypeNotFoundException extends RuntimeException {
|
||||
public BoardTypeNotFoundException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
@@ -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> {
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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";
|
||||
}
|
||||
}
|
||||
@@ -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";
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.example.restcontroller.notice.exception;
|
||||
|
||||
public class AlreadyDeletedException extends RuntimeException {
|
||||
|
||||
public AlreadyDeletedException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.example.restcontroller.notice.exception;
|
||||
|
||||
public class DuplicateNoticeException extends RuntimeException {
|
||||
|
||||
public DuplicateNoticeException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.example.restcontroller.notice.exception;
|
||||
|
||||
public class NoticeNotFoundException extends RuntimeException{
|
||||
|
||||
public NoticeNotFoundException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
package com.example.restcontroller.notice.model;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class NoticeDeleteInput {
|
||||
|
||||
List<Long> idList;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.example.restcontroller.user.exception;
|
||||
|
||||
public class ExistsEmailException extends RuntimeException {
|
||||
public ExistsEmailException(String s) {
|
||||
super(s);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package com.example.restcontroller.user.exception;
|
||||
|
||||
public class PasswordNotMatchException extends RuntimeException {
|
||||
public PasswordNotMatchException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package com.example.restcontroller.user.exception;
|
||||
|
||||
public class UserNotFoundException extends RuntimeException{
|
||||
|
||||
public UserNotFoundException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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> {
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
39
rest-controller-practice/src/main/resources/application.yml
Normal file
39
rest-controller-practice/src/main/resources/application.yml
Normal 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
|
||||
51
rest-controller-practice/src/main/resources/data.sql
Normal file
51
rest-controller-practice/src/main/resources/data.sql
Normal 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);
|
||||
@@ -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() {
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user