엔티티를 만들 때 오류가 있었다..😥
SaleEntity에서 ManyToOne이라고 해야하는데 ManyToAny라고 했드라..그래서 수정해준다!!
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_idx", referencedColumnName = "idx", updatable = false, nullable = false)
private UserEntity userEntity;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "category_idx", referencedColumnName = "idx", updatable = false, nullable = false)
private CategoryEntity categoryEntity;
h2DB를 사용할 거라 yml수정이랑 resource에 sql문을 넣어놓겠다.
application.yml
# yml이랑 같다
spring:
thymeleaf:
cache: false
datasource:
url: jdbc:h2:mem:farmerstory
driverClassName: org.h2.Driver
username: sa
password:
h2:
console:
enabled: true
path: /h2-console
sql:
init:
encoding: UTF-8
schema-locations: classpath:h2/schema.sql
# dataLocations: classpath:h2/data.sql
mode: always
jpa:
defer-datasource-initialization: true
open-in-view: false # 트랜잭션 범위 밖에서 영속성 컨텍스트를 유지할지 여부
database-platform: org.hibernate.dialect.H2Dialect
hibernate:
ddl-auto: none # create-drop, update, validate, none
naming:
physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
implicit-strategy: org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyJpaImpl
show-sql: true
properties:
hibernate:
format_sql: true # 정렬
use_sql_comments: true
servlet:
multipart:
max-request-size: 10MB
max-file-size: 10MB
data.sql
DBeaver로 테이블 만들고 DDL을 가져온 것이다.
-- 유저테이블
INSERT INTO `user` (`idx`, `nickname`, `id`, `password`, `email`, `profile`, `authority`)
VALUES (1, '관리자', 'admin', 'admin', 'admin@admin.com', NULL, '3'),
(2, '농부', 'farmer', '1234', 'farmer@naver.com', NULL, '1'),
(3, '일반인', 'temp', '1234', 'temp@naver.com', NULL, '2');
-- 카테고리테이블
INSERT INTO `category` (`idx`, `name`)
VALUES (1, '곡류'),
(2, '콩류'),
(3, '서류'),
(4, '채소'),
(5, '과실류'),
(6, '종실류'),
(7, '특용작물'),
(8, '약용작물'),
(9, '전매작물'),
(10, '화훼작물'),
(11, '버섯류');
schema.sql
DDL을 가져와서 넣어줬다.
하지만 무작정 넣으면 안된다!!
H2 데이터베이스에서는 int(11)과 같은 숫자에 괄호를 사용하여 데이터 타입의 길이를 지정할 수 없기 때문에 int로 변경해야 한다.
또한 폴인키가 연결되어 있기 때문에 난 하나씩 넣을 생각이다.
일단 유저 테이블이랑 카테고리 테이블 필요해서 넣었다!
-- farmerstory.`user` definition
CREATE TABLE `user` (
`idx` int NOT NULL AUTO_INCREMENT COMMENT '유저 번호',
`nickname` varchar(100) NOT NULL COMMENT '유저닉네임',
`id` varchar(100) NOT NULL COMMENT '유저id',
`password` varchar(100) NOT NULL COMMENT '유저password',
`email` varchar(100) NOT NULL COMMENT '유저email',
`profile` longtext DEFAULT NULL COMMENT '유저 profile',
`authority` varchar(100) NOT NULL COMMENT '권한(1은 farmer, 2는 일반)',
PRIMARY KEY (`idx`)
);
entity에서 가져올 Repository를 만들어준다.
package com.example.farmerstroy.model.user.repository;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;
import com.example.farmerstroy.model.user.entity.UserEntity;
public interface UserRepository extends JpaRepository<UserEntity, Long>{
Optional <UserEntity> findById(String id);
}
난 id를 찾아오는 것만 필요해서 일단 이렇게 만들었다.
아 하기 전에 DTO를 하나 만들어준다.
화면에 필요한 것들만 적어준다.
package com.example.farmerstroy.domain.auth.dto;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
@NoArgsConstructor
@AllArgsConstructor
@Getter
public class ReqJoinDTO {
@Valid
@NotNull(message = "회원 정보를 입력해주세요")
private User user;
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Getter
public static class User{
@NotBlank(message = "닉네임을 입력해주세요")
private String nickname;
@NotBlank(message = "아이디를 입력해주세요")
private String id;
@NotBlank(message = "비밀번호를 입력해주세요")
private String psssword;
@NotBlank(message = "이메일을 입력해주세요")
private String email;
}
}
여기서 @Valid어노테이션이 오류가 난다.
build.gradle에 꼭 붙여준다.implementation 'org.springframework.boot:spring-boot-starter-validation'
<br>
## ResponseDTO.java
그리고 응답 DTO를 만들어준다
```java
package com.example.farmerstroy.common.dto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Getter
public class ResponseDTO<T> {
private Integer code;
private String message;
private T data;
}
repository가 가져온 것을 service로 가공해준다.
주석으로 설명을 어떤 걸 구현했는지 적어놨다!
package com.example.farmerstroy.domain.auth.service;
import java.util.Optional;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.example.farmerstroy.common.dto.ResponseDTO;
import com.example.farmerstroy.domain.auth.dto.ReqJoinDTO;
import com.example.farmerstroy.model.user.entity.UserEntity;
import com.example.farmerstroy.model.user.repository.UserRepository;
import lombok.RequiredArgsConstructor;
@Service
@RequiredArgsConstructor
@Transactional(readOnly = true)
public class AuthServiceApiV1 {
private final UserRepository userRepository;
public ResponseEntity<?> join(ReqJoinDTO dto){
// 회원가입 정보 입력했는지 확인
if (dto.getUser().getId() == null ||
dto.getUser().getId().equals("") ||
dto.getUser().getPsssword() == null ||
dto.getUser().getPsssword().equals("") ||
dto.getUser().getNickname() == null ||
dto.getUser().getNickname().equals("") ||
dto.getUser().getEmail() == null ||
dto.getUser().getEmail().equals("")
) {
return new ResponseEntity<>(
ResponseDTO.builder()
.code(1)
.message("아이디나 비밀번호, 이름, 이메일을 입력해주세요")
.build()
,HttpStatus.BAD_REQUEST
);
}
//리파지토리에서 아이디로 유저 찾기
Optional<UserEntity> userEntityOptional = userRepository.findById(dto.getUser().getId());
// 있으면 있다고 메시지 리턴
if (userEntityOptional.isPresent()) {
return new ResponseEntity<>(
ResponseDTO.builder()
.code(1)
.message("이미 존재하는 아이디입니다.")
.build()
,HttpStatus.BAD_REQUEST
);
}
// 없으면 회원가입 처리
UserEntity userEntity = UserEntity.builder()
.id(dto.getUser().getId())
.password(dto.getUser().getPsssword())
.nickname(dto.getUser().getNickname())
.email(dto.getUser().getEmail())
.build();
userRepository.save(userEntity);
// 응답데이터로 리턴하기
return new ResponseEntity<>(
ResponseDTO.builder()
.code(0)
.message("회원가입에 성공하였습니다.")
.build(),
HttpStatus.OK
);
}
}
데이터를 뿌려주기 위한 controller를 만들어준다.
package com.example.farmerstroy.domain.auth.controller;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.example.farmerstroy.domain.auth.dto.ReqJoinDTO;
import com.example.farmerstroy.domain.auth.service.AuthServiceApiV1;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
@RestController
@RequiredArgsConstructor
@RequestMapping("/api/v1/auth")
public class AuthControllerApiV1 {
private final AuthServiceApiV1 authServiceApiV1;
@PostMapping("/join")
public ResponseEntity<?> join(@Valid @RequestBody ReqJoinDTO dto){
return authServiceApiV1.join(dto);
}
}
이제 실행해본다
(두근두근..)
started가 떴다..하
포스트맨을 실행해본다..
오류..ㅎㅎㅎ
authority가 not null로 되어 있는데 안해줘서 그렇다..
그래서 임시로 1로 넣어서 해준다..
여기에 넣어준다.
// 없으면 회원가입 처리
UserEntity userEntity = UserEntity.builder()
.id(dto.getUser().getId())
.password(dto.getUser().getPassword())
.nickname(dto.getUser().getNickname())
.email(dto.getUser().getEmail())
.authority(1)
.build();
실행하면 성공!!!!

h2에 들어가서 확인하면

됐다!!!!!
script를 만들오부자꾸나
아 그전에 badrequest만 처리할 수 있도록 만든다.
예외를 처리해준다.
package com.example.farmerstroy.common.exception;
public class BadRequestException extends RuntimeException{
public BadRequestException(String message){
super(message);
}
public BadRequestException(){
super("잘못된 요청입니다.");
}
}
그럼 이렇게 처리할 수 있다.
// 회원가입 정보 입력했는지 확인
if (dto.getUser().getId() == null ||
dto.getUser().getId().equals("") ||
dto.getUser().getPassword() == null ||
dto.getUser().getPassword().equals("") ||
dto.getUser().getNickname() == null ||
dto.getUser().getNickname().equals("") ||
dto.getUser().getEmail() == null ||
dto.getUser().getEmail().equals("")
) {
// return new ResponseEntity<>(
// ResponseDTO.builder()
// .code(1)
// .message("아이디나 비밀번호, 이름, 이메일을 입력해주세요")
// .build()
// ,HttpStatus.BAD_REQUEST
// );
throw new BadRequestException("아이디나 비밀번호, 이름, 이메일을 입력해주세요");
}
//리파지토리에서 아이디로 유저 찾기
Optional<UserEntity> userEntityOptional = userRepository.findById(dto.getUser().getId());
// 있으면 있다고 메시지 리턴
if (userEntityOptional.isPresent()) {
// return new ResponseEntity<>(
// ResponseDTO.builder()
// .code(1)
// .message("이미 존재하는 아이디입니다.")
// .build()
// ,HttpStatus.BAD_REQUEST
// );
throw new BadRequestException("이미 존재합니다.");
}
실행하면 요렇게!!

db도 요렇게 된다!!

값을 null로 하면

입력하라고 아래 message가 뜬다.
<script>
// 회원가입 요청
// 회원가입 버튼을 누르면 실행되는 함수
const requestJoin = () => {
// 회원가입 요청
const dto = {
user: {
nickname: document.querySelector("#nickname").value,
id: document.querySelector("#id").value,
password: document.querySelector("#password").value,
email: document.querySelector("#email").value,
},
};
fetch("/api/v1/auth/join",{
method : "POST",
headers : {
"Content-Type" : "application/json;charset=utf-8"
},
body : JSON.stringify(dto)
})
.then((response) => response.json())
.then((result) => {
alert(result.message);
if (result.code === 0) {
// 회원가입 성공
location.replace("/login");
}
})
};
</script>
실행하면!!

db도!!

<script>
// 회원가입 요청
// 회원가입 버튼을 누르면 실행되는 함수
const requestJoin = () => {
// 서버와 통신하기 전에 입력값 검증
if (!validateFields()) {
return;
}
// 회원가입 요청
const dto = {
user: {
nickname: document.querySelector("#nickname").value,
id: document.querySelector("#id").value,
password: document.querySelector("#password").value,
email: document.querySelector("#email").value,
},
};
fetch("/api/v1/auth/join",{
method : "POST",
headers : {
"Content-Type" : "application/json;charset=utf-8"
},
body : JSON.stringify(dto)
})
.then((response) => response.json())
.then((result) => {
alert(result.message);
if (result.code === 0) {
// 회원가입 성공
location.replace("/login");
}
})
};
// 유효성 검사
const validateFields = () => {
// id 속성을 이용해서 해당하는 요소를 가져온다
const nicknameElement = document.querySelector("#nickname");
const idElement = document.querySelector("#id");
const passwordElement = document.querySelector("#password");
const passwordCheckElement = document.querySelector("#passwordCheck");
const emailElement = document.querySelector("#email");
// 값들이 비어있는지 확인
if (nicknameElement.value === "") {
alert("닉네임을 확인해주세요");
nicknameElement.focus();
return false;
}
if (idElement.value === "") {
alert("아이디를 입력해주세요");
idElement.focus();
return false;
}
if (passwordElement.value === "") {
alert("비밀번호를 입력해주세요");
passwordElement.focus();
return false;
}
if (passwordElement.value !== passwordCheckElement.value) {
alert("비밀번호가 일치하지 않습니다.");
passwordCheckElement.focus();
return false;
}
if (emailElement.value === "") {
alert("이메일을 입력해주세요");
emailElement.focus();
return false;
}
return true;
}
</script>


아이디를 두글자 밑으로 작성시 오류가 나도록 만들어본다.
어노테이션들을 이용해 설정한다.
package com.example.farmerstroy.domain.auth.dto;
import jakarta.validation.Valid;
import jakarta.validation.constraints.Email;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Pattern;
import jakarta.validation.constraints.Size;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;
@NoArgsConstructor
@AllArgsConstructor
@Getter
public class ReqJoinDTO {
@Valid
@NotNull(message = "회원 정보를 입력해주세요")
private User user;
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Getter
public static class User{
@NotBlank(message = "닉네임을 입력해주세요")
@Pattern(regexp = "^[가-힣a-zA-Z0-9]{2,10}$" , message = "닉네임은 특수문자를 포함하지 않은 2~10자리여야 합니다.")
private String nickname;
@NotBlank(message = "아이디를 입력해주세요")
@Pattern(regexp = "^[a-z0-9]{4,20}$", message = "아이디는 영어 소문자와 숫자만 사용하여 4~20자리여야 합니다.")
private String id;
@NotBlank(message = "비밀번호를 입력해주세요")
@Size(min = 4, max = 20, message = "비밀번호는 4자 이상 20자 이하로 입력해주세요.")
private String password;
@NotBlank(message = "이메일 주소를 입력해주세요.")
@Email(message = "올바른 이메일 주소를 입력해주세요.")
private String email;
}
}
그럼 이제 양식에 맞지 않게 입력하면 오류가 뜰 것인데 다 처리해주면 느려져서 한꺼번에 처리하도록 하겠다.
어떤 오류도 이 handler를 통해 처리된다.
package com.example.farmerstroy.common.exception.handler;
import java.util.HashMap;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import com.example.farmerstroy.common.dto.ResponseDTO;
import com.example.farmerstroy.common.exception.BadRequestException;
@RestControllerAdvice
// Rest방식으로 에러 처리
public class RestExceptionHandler {
@ExceptionHandler(BindException.class)
public ResponseEntity<?> handleBindException(BindException bindException){
HashMap<String, String> errorMap = new HashMap<>();
for (FieldError fieldError : bindException.getBindingResult().getFieldErrors()) {
errorMap.put(fieldError.getField(), fieldError.getDefaultMessage());
}
return new ResponseEntity<>(
ResponseDTO.builder()
.code(1)
.message("요청 데이터를 확인해주세요")
.data(errorMap)
.build(),
HttpStatus.BAD_REQUEST
);
}
// 처리할 에러를 특정함
@ExceptionHandler(BadRequestException.class)
public ResponseEntity<?> handleBadRequestException(Exception exception) {
exception.printStackTrace();
return new ResponseEntity<>(ResponseDTO.builder()
.code(1)
.message(exception.getMessage())
.build(), HttpStatus.BAD_REQUEST);
}
// 모든 에러를 처리할 때
// 이렇게 하면 찾아내기 어려움
// class별로 에러를 처리하는게 나음
// @ExceptionHandler(Exception.class)
// public ResponseEntity<?> handleException(Exception exception){
// exception.printStackTrace();// 콘솔창에 에러를 뿌려주고 화면에 뿌려줌(하고 싶으면 하고)
// return new ResponseEntity<>(ResponseDTO.builder()
// .code(1)
// .message(exception.getMessage())
// .build(), HttpStatus.INTERNAL_SERVER_ERROR);
// }
}
계속 하면서 data.sql을 만들어 놨는데 h2db에 들어가지 않았다.
그래서 보니 yml에 data.sql을 주석을 해놓고 유저 테이블은 만들어 졌으나 카테고리 테이블이 만들어지지 않았다!
데이터만 있고 테이블이 만들어지지 않았던 거다
오류를 고쳐본다.
# yml이랑 같다
spring:
thymeleaf:
cache: false
datasource:
url: jdbc:h2:mem:farmerstory
driverClassName: org.h2.Driver
username: sa
password:
h2:
console:
enabled: true
path: /h2
sql:
init:
encoding: UTF-8
schema-locations: classpath:h2/schema.sql
dataLocations: classpath:h2/data.sql
mode: always
jpa:
defer-datasource-initialization: true
open-in-view: false # 트랜잭션 범위 밖에서 영속성 컨텍스트를 유지할지 여부
database-platform: org.hibernate.dialect.H2Dialect
hibernate:
ddl-auto: none # create-drop, update, validate, none
naming:
physical-strategy: org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
implicit-strategy: org.hibernate.boot.model.naming.ImplicitNamingStrategyLegacyJpaImpl
show-sql: true
properties:
hibernate:
format_sql: true # 정렬
use_sql_comments: true
servlet:
multipart:
max-request-size: 10MB
max-file-size: 10MB
추가 시켜준다.
-- farmerstory.category definition
CREATE TABLE `category` (
`idx` int NOT NULL COMMENT 'Category Index',
`name` varchar(100) NOT NULL COMMENT 'Category Name',
PRIMARY KEY (`idx`)
);
h2db를 사용할꺼니깐 mysql은 주서처리해준다.
// implementation 'mysql:mysql-connector-java'
그러고 실행하면 data가 잘 들어오는 걸 볼 수 있다.
