오늘 고민한 것
엘라스틱서치를 써보는것이 어떨까?
- 구체적인 기능과 예시가 있었으면 선뜻 쓸텐데 그렇지 않으면 애매한 거 같다, 쓰는 이유를 정말 구체적으로 만드는게 좋을 거 같다
- Q.엘라스틱서치를 쓸만큼의 데이터를 어떻게 구하지 그걸 어떻게 만들지
- 검색이나 인덱스 걸기 → 엘라스틱서치 무조건 좋다
- 잘쓰고 못쓰고보다 쓰고 안쓰고가 더 중요할 때가 있다 → 면접관한테 이력서를 보여주려면 억지로라도 쓰는게 좋다고 생각한다
프론트 구현 무엇으로 할 건지 : Thymeleaf & Vue & React
- 처음 배우기 시작 할 때는 ajax/thymeleaf 가 배우기에 빠르긴 하다.
- Vue 문법이 Thymeleaf 스럽다 ⇒ 참조할 템플릿이 많아 작업에 용이 할 수 있음.
- ⇒장기적 관점에서의 시간 절약
- Thymeleaf로 진행을 할 거면 restApi를 지키는 쪽으로 하자.
- 최대한 시간을 절약 할 수 있는 방안으로 택하자
- 웹소켓을 열면 Client 라이브러리는 Vue 나 React에 붙이기가 더 쉬울 것
채팅에 Redis 조합
- 채팅 DB를 Redis로 두었을 때 → 로그아웃이나 컴퓨터를 끄면 날아간다는 소리가 있는데
- 서비스를 내렸을 때 데이터들이 날아간다
- 채팅 서비스는 영속적이어야 한다.
- ⇒ 현 구상대로 짧은 유지기간 후 데이터를 날려버리는 건 아쉽다.
- MongoDB가 괜찮은 방안이 될 수 있다.
오늘 알게된 것
1. Spring project의 group 이름 바꾸기
group name 변경하기
실행 버튼 옆 ...을 눌러서 Application중 group name이 잘못되어 있는것을 삭제해준다
2. git ignore에 파일 추가
/application-*.yml
이렇게 하면 application-db, application-key 이렇게 써지는거 다 빠짐
3. git commit 취소
git rm -r --cached src/main/resources/application-db.yml
git reset --soft [commit id]
4. Map을 Value기준으로 정렬하는 방법
Map의 entry를 List에 넣고 람다식으로 sorting한다
Map<String, Integer> map = new HashMap<>();
map.put("a", 3);
map.put("b", 2);
map.put("c", 1);
//정렬
List<Map.Entry<String, Integer>> entryList = new LinkedList<>(map.entrySet());
entryList.sort(((o1, o2) -> map.get(o1.getKey()) - map.get(o2.getKey())));
//출력
for(Map.Entry<String, Integer> entry : entryList){
System.out.println("key : " + entry.getKey() + ", value : " + entry.getValue());
}
오늘 한 일
- Post creation 파트 개발
- Bean validation 진화시키기
메뉴랑도 상관이 있으니까 메뉴 파트도 내가 만듦
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Entity
@Table(name = "TB_POST")
public class Post {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private String address;
@Column(nullable = false)
private String store;
@Column(nullable = false)
private Long minPrice;
@Column(nullable = false)
private Long deliveryCost;
@OneToMany(mappedBy = "post")
private List<Menu> menus;
@Column
private Long sumPrice;
@Column(nullable = false)
private LocalDateTime deadline;
}
→ sumPrice랑
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Entity
@Table(name = "TB_MENU")
public class Menu {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne
@OnDelete(action = OnDeleteAction.CASCADE)
@JoinColumn(name = "post_id", nullable = false)
private Post post;
@NotBlank
private String menuname;
@NotNull
private Long price;
}
@Getter
@EntityListeners(AuditingEntityListener.class)
@MappedSuperclass
public class BaseTime {
@CreatedDate
@Column(updatable = false)
@Temporal(TemporalType.TIMESTAMP)
private LocalDateTime createdAt;
@LastModifiedDate
@Column
@Temporal(TemporalType.TIMESTAMP)
private LocalDateTime modifiedAt;
}
이거에 대한
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Entity
@Table(name = "TB_POST")
public class Post {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Column(nullable = false)
private String address;
@Column(nullable = false)
private String store;
@Column(nullable = false)
private Long minPrice;
@Column(nullable = false)
private Long deliveryCost;
@OneToMany(mappedBy = "post")
private List<Menu> menus;
@Column
private Long sumPrice;
@Column
private LocalDateTime deadline;
}
시간 빼기/ 더하기 부분 구현
근데 category 까먹음
category 추가함
package com.moayo.moayoeats.domain.post.entity;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
@Getter
@RequiredArgsConstructor
public enum CategoryEnum {
BURGER("햄버거"),
CHICKEN("치킨"),
PIZZA("피자"),
KOREAN("한식"),
SNACK("분식"),
WESTERN("양식"),
ASIAN("아시안"),
JAPANESE("일식"),
CHINESE("중식"),
LUNCHBOX("도시락");
private final String category;
}
에러 출력 어떻게 되는지 보려고 이거저거 해봄
⭐LocalDateTime plus, minus 함수
LocalDateTime은 plus, minus 함수를 제공하며 날짜, 시간을 더하거나 뺄 수 있습니다.
- plus/minusMonths()
- plus/minusDays()
- plus/minusHours()
- plus/minusMinutes()
- plus/minusSeconds()
import java.time.LocalDateTime;
public class Example {
public static void main(String[] args) {
LocalDateTime now = LocalDateTime.now();
System.out.println(now);
LocalDateTime result = now.plusYears(10)
.plusMonths(10)
.plusDays(10)
.plusHours(10)
.plusMinutes(10)
.plusSeconds(10);
System.out.println(result);
result = now.minusYears(10)
.minusMonths(10)
.minusDays(10)
.minusHours(10)
.minusMinutes(10)
.minusSeconds(10);
System.out.println(result);
}
}
Output:
2022-12-17T06:17:00.4958389392033-10-27T16:27:10.4958389392012-02-06T20:06:50.495838939
LocalDateTime.java 안에 가서 봄!
//-----------------------------------------------------------------------
/**
* Returns a copy of this {@code LocalDateTime} with the specified number of hours added.
* <p>
* This instance is immutable and unaffected by this method call.
*
* @param hours the hours to add, may be negative
* @return a {@code LocalDateTime} based on this date-time with the hours added, not null
* @throws DateTimeException if the result exceeds the supported date range
*/
public LocalDateTime plusHours(long hours) {
return plusWithOverflow(date, hours, 0, 0, 0, 1);
}
/**
* Returns a copy of this {@code LocalDateTime} with the specified number of minutes added.
* <p>
* This instance is immutable and unaffected by this method call.
*
* @param minutes the minutes to add, may be negative
* @return a {@code LocalDateTime} based on this date-time with the minutes added, not null
* @throws DateTimeException if the result exceeds the supported date range
*/
public LocalDateTime plusMinutes(long minutes) {
return plusWithOverflow(date, 0, minutes, 0, 0, 1);
}
public void createPost(PostRequest postReq){
//set deadline to mins after
LocalDateTime now = LocalDateTime.now();
LocalDateTime deadline = now.plusMinutes(postReq.deadline().getMins());
Post post = Post.builder()
.address(postReq.address())
.store(postReq.store())
.deliveryCost(postReq.deliveryCost())
.minPrice(postReq.minPrice())
.deadline(deadline)
.category(postReq.category())
.build();
postRepository.save(post);
}
이렇게 하니까 잘 된다!
Bean validation 진화시키기
AOP처리를 하는데 무슨 에러인지 뽑아서 보여주고 싶음
BindingResult.java
public interface BindingResult extends Errors {
-> public interface getFieldErrors가보니까
/**
* Get all errors associated with a field.
* @return a List of {@link FieldError} instances
* @see #getGlobalErrors()
*/
List<FieldError> getFieldErrors();
이게 있음
public class FieldError extends ObjectError{
public FieldError(String objectName, String field, @Nullable Object rejectedValue, boolean bindingFailure,
@Nullable String[] codes, @Nullable Object[] arguments, @Nullable String defaultMessage) {
private final String field;
@Nullable
private final Object rejectedValue;
private final boolean bindingFailure;
super(objectName, codes, arguments, defaultMessage);
Assert.notNull(field, "Field must not be null");
this.field = field;
this.rejectedValue = rejectedValue;
this.bindingFailure = bindingFailure;
}
@ExceptionHandler(MethodArgumentNotValidException.class)
public ApiResponse<List<String>> handleMethodArgumentNotValidException(BindingResult bindingResult) {
List<String> errors = bindingResult.getFieldErrors().stream()
.map((FieldError fieldError)->
fieldError.getRejectedValue()+"가 "+
fieldError.getField()+"의 형식에 맞지 않습니다."
)
.toList();
return new ApiResponse<>(HttpStatus.BAD_REQUEST.value(), "입력값이 잘못되었습니다", errors);
}
{
"address":"주소주소",
"store": "가게가게",
"minPrice": 20000,
"deliveryCost":2000,
"deadline":"M60"
}
{
"status": 201,
"message": "글을 생성했습니다.",
"data": null
}
deadline잘 들어감
에러 출력 어떻게 되는지 보려고 이거저거 해봄
{
"address":"주소주소",
"store": "",
"minPrice": 20000,
"deliveryCost":2000,
"deadline":"M60"
}
@ExceptionHandler(MethodArgumentNotValidException.class)
public ApiResponse<List<String>> handleMethodArgumentNotValidException(BindingResult bindingResult) {
List<String> errors = bindingResult.getFieldErrors().stream()
.map((FieldError fieldError)->
fieldError.getRejectedValue()+"가 "+
fieldError.getField()+"의 형식에 맞지 않습니다."
)
.toList();
return new ApiResponse<>(HttpStatus.BAD_REQUEST.value(), "입력값이 잘못되었습니다", errors);
}
로그에만 이렇게 찍히고 화면에는 출력값이 안 나옴
[Field error in object 'postRequest' on field 'store': rejected value [];
알고보니 ExceptionHandler 클래스 대신 Exception안에서 저러고 있었음
→ ExceptionHandler 클래스 만들어줌
package com.moayo.moayoeats.global.exception;
import com.moayo.moayoeats.global.dto.ApiResponse;
import java.util.List;
import org.springframework.http.HttpStatus;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(GlobalException.class)
public ApiResponse<?> handleGlobalException(GlobalException globalException){
ErrorCode errorCode = globalException.getErrorCode();
return new ApiResponse<>(errorCode.getHttpStatus(), errorCode.getMessage());
}
@ExceptionHandler(MethodArgumentNotValidException.class)
public ApiResponse<List<String>> handleMethodArgumentNotValidException(
BindingResult bindingResult) {
List<String> errors = bindingResult.getFieldErrors().stream()
.map((FieldError fieldError)->
fieldError.getField()+"가 "+
fieldError.getDefaultMessage()
)
.toList();
return new ApiResponse<>(HttpStatus.BAD_REQUEST.value(), "입력값이 잘못되었습니다", errors);
}
}
{
"status": 400,
"message": "입력값이 잘못되었습니다",
"data": [
"store가 must not be blank"
]
}
잘 됨!
근데 또 저 field랑 defaultmessage는 RuntimeException에도 있나 싶어져서 그거 분류하는것도 만듦
public class RuntimeException extends Exception {
->
public class Exception extends Throwable {
->
public class Throwable implements Serializable {
/** use serialVersionUID from JDK 1.0.2 for interoperability */
@java.io.Serial
private static final long serialVersionUID = -3042686055658047285L;
/**
* The JVM saves some indication of the stack backtrace in this slot.
*/
private transient Object backtrace;
/**
* Specific details about the Throwable. For example, for
* {@code FileNotFoundException}, this contains the name of
* the file that could not be found.
*
* @serial
*/
private String detailMessage;
->
이건 나중에 하기!
@ExceptionHandler(RuntimeException.class)
public ApiResponse<List<String>> handleRuntimeException(
BindingResult bindingResult) {
List<String> errors = bindingResult.getFieldErrors().stream()
.map((FieldError fieldError) -> fieldError.getField() + fieldError.getDefaultMessage())
.toList();
return new ApiResponse<>(HttpStatus.BAD_REQUEST.value(), "입력값이 잘못되었습니다", errors);
}
'개발일지' 카테고리의 다른 글
2023-01-10, Today I Learned (0) | 2024.01.10 |
---|---|
2024-01-09, Today I Learned @IdClass Composite key in Spring (0) | 2024.01.09 |
2024-01-03, Today I Learned (0) | 2024.01.03 |
2024-01-02, Today I Learned (0) | 2024.01.02 |
2023-12-28, Today I Learned (1) | 2023.12.28 |