일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- 최소공배수
- 자바 최소공배수
- 스프링뼈대
- 자바 유클리드
- string과 stringbuilder
- 자바 최대공약수
- 최대공약수
- 모던자바
- string
- islowercase()
- 동일성과 동등성
- addDoc
- toLowerCase()
- 래퍼타입
- 프로그래머스 레벨1
- ineer join
- 스프링환경설정
- 자바 스트링
- Git사용법
- sql 데이터형 변환
- 최대공약수와 최소공배수
- 베주계수
- 스프링
- git 컨벤션
- 유클리드호제법
- StringBuilder
- isuppercase()
- while과 two-pointer
- replaceAll()
- stringbuilder의 reverse()
- Today
- Total
주노 님의 블로그
20241002 본캠프 55일차 TIL 본문
본캠프 55일차 내용 간단요약
- 13:00 ~ 18:00 : 개인과제
- 18:00 ~ 19:00 : 저녁시간
- 19:00 ~ 21:00 : 개인과제
오늘 해야할 일 ✔️ 🔺 ❌
✔️개인과제 1단계 까지 듣기
Level 01
org.springframework.orm.jpa.JpaSystemException: could not execute statement [Connection is read-only. Queries leading to data modification are not allowed] [insert into todos (contents,created_at,modified_at,title,user_id,weather) values (?,?,?,?,?,?)]
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1022) ~[spring-webmvc-6.1.12.jar:6.1.12]
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:914) ~[spring-webmvc-6.1.12.jar:6.1.12]
대충 위와같은 오류가 뜬다
at org.example.expert.domain.todo.service.TodoService.saveTodo(TodoService.java:39) ~[main/:na]
public TodoSaveResponse saveTodo(AuthUser authUser, TodoSaveRequest todoSaveRequest) {
User user = User.fromAuthUser(authUser);
String weather = weatherClient.getTodayWeather();
Todo newTodo = new Todo(
todoSaveRequest.getTitle(),
todoSaveRequest.getContents(),
weather,
user
);
Todo savedTodo = todoRepository.save(newTodo);
return new TodoSaveResponse(
savedTodo.getId(),
savedTodo.getTitle(),
savedTodo.getContents(),
weather,
new UserResponse(user.getId(), user.getEmail())
);
}
todo 위 메서드에서 오류가뜨는것을 발견했고
@Transactional(readOnly = true)
상단에 트랜잭셔널 readOnly ture가 되어있었다.
아니 읽기전용인데 너는 왜 쓰고있니? 라는 오류같았다.
위 메서드에 get todo 관련 메서드와 save todo 메서드가 하나만 있길래 save todo에 트랜잭션을 걸어주었다.
Level 02
user에 nickname 추가 jwt에 nickname 추가
JwtUtil.java
.claim("nickname", nickname)
JwtFilter.java
httpRequest.setAttribute("nickname", claims.get("nickname"));
AuthUserArgumentResolver.java
UserRole userRole = UserRole.of((String) request.getAttribute("userRole"));
User.java
public static User fromAuthUser(AuthUser authUser) {
return new User(authUser.getId(), authUser.getEmail(),authUser.getNickname(), authUser.getUserRole());
}
AuthUser.java
private final UserRole userRole;
그외 우수수수수...
토큰을 만들때 nickname을 claim으로 넣어주고, authuser에서 받아오는 코드에 모드 nickname을 넣어준다.
level03
UserAdminController 클래스의 changeUserRole() 메소드가 실행 전 동작해야해요.
AdminAccessLoggingAspect 클래스에 있는 AOP가 개발 의도에 맞도록 코드를 수정해주세요.
@After("execution(* org.example.expert.domain.user.controller.UserController.getUser(..))")
@After 어노테이션이 되어있다.
@Before 어노테이션을 달아주자.
httpRequest.setAttribute("userRole", claims.get("userRole"));
또한 userole을 조회하기위해
if(request.getAttribute("userRole").equals("ADMIN"))
{
log.info(
"Admin Access Log - User ID: {}, Request Time: {}, Request URL: {}, Method: {}",
userId, requestTime, requestUrl, joinPoint.getSignature().getName());
}
위처럼 작성하였다
user controller의 getuser을 사용해서 조회를 해보자.
결과는 아래와같다
2024-10-02T16:14:55.013+09:00 INFO 4768 --- [nio-8080-exec-3] o.e.expert.aop.AdminAccessLoggingAspect : Admin Access Log - User ID: 5, Request Time: 2024-10-02T16:14:55.013127800, Request URL: /users/5, Method: getUser
[Hibernate]
select
u1_0.id,
u1_0.created_at,
u1_0.email,
u1_0.modified_at,
u1_0.nickname,
u1_0.password,
u1_0.user_role
from
users u1_0
where
u1_0.id=?
level04
컨트롤러 테스트코드가 실패한다고 한다
@Test
void todo_단건_조회_시_todo가_존재하지_않아_예외가_발생한다() throws Exception {
// given
long todoId = 1L;
// when
when(todoService.getTodo(todoId))
.thenThrow(new InvalidRequestException("Todo not found"));
// then
mockMvc.perform(get("/todos/{todoId}", todoId))
.andExpect(status().isOk())
.andExpect(jsonPath("$.status").value(HttpStatus.OK.name()))
.andExpect(jsonPath("$.code").value(HttpStatus.OK.value()))
.andExpect(jsonPath("$.message").value("Todo not found"));
}
코드를 보면 when에서 then throw를 던지고는
perform에서는 isOk를 날리는것을 볼 수 있다.
@Test
void todo_단건_조회_시_todo가_존재하지_않아_예외가_발생한다() throws Exception {
// given
long todoId = 1L;
// when
when(todoService.getTodo(todoId))
.thenThrow(new InvalidRequestException("Todo not found"));
// then
mockMvc.perform(get("/todos/{todoId}", todoId))
.andExpect(status().is4xxClientError())
.andExpect(jsonPath("$.status").value(HttpStatus.BAD_REQUEST.name()))
.andExpect(jsonPath("$.code").value(HttpStatus.BAD_REQUEST.value()))
.andExpect(jsonPath("$.message").value("Todo not found"));
}
400error로 바꿔주자.
level 05
todo 조회에서 weather과 update date를 기준으로 검색하는 코드로 바꾸세요
public Page<TodoResponse> getTodos(int page, int size, String weather, String startUpdateDate, String endUpdateDate)
{
startUpdateDate += " 00:00:00";
endUpdateDate += " 23:59:59";
Pageable pageable = PageRequest.of(page - 1, size);
LocalDateTime startLocalDate = LocalDateTime.parse(startUpdateDate, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
LocalDateTime endLocalDate = LocalDateTime.parse(endUpdateDate, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
Page<Todo> todos = todoRepository.findAllByWeatherAndBetweenUpdateDate(pageable, weather, startLocalDate, endLocalDate);
date를 쿼리 파라미터로 받아준다음 auditing된 date가 localdatetime이라 localdatetime으로 변환해준다.
@Query("SELECT t FROM Todo t"
+ " LEFT JOIN FETCH t.user u"
+ " WHERE (:weather IS NULL OR t.weather = :weather) AND t.modifiedAt between :startLocalDate and :endLocalDate"
+ " ORDER BY t.modifiedAt DESC")
Page<Todo> findAllByWeatherAndBetweenUpdateDate(Pageable pageable, String weather,
LocalDateTime startLocalDate, LocalDateTime endLocalDate);
쿼리는 이렇게 만들어준다
where 에서 weather과 같거나, null이고, modified at이 사이값이라면..
참고자료
https://developer-joon.tistory.com/171
level6
눅아 실수로 지워!!!!!!!!!!!!!!!!!!!
cascade타입을 추가해서
todo가 추가되면 manager로 자동 추가되게 하라
@OneToMany(mappedBy = "todo", cascade = {CascadeType.REMOVE, CascadeType.PERSIST})
private List<Manager> managers = new ArrayList<>();
cascade 타입에 대해서 짚고 넘어가자
PERSIST : 부모 엔티티가 저장될때 자식 엔티티도 같이 저장된다
MERGE : 부모 엔티티가 병합 될때 자식 엔티티도 병합이된다
REMOVE : 부모 엔티티가 삭제될때 자식엔티티도 삭제
REFRESH : 부모 엔티티가 새로고침 될때 자식 엔티티도 새로고침 됨(?)
DETACH : 부모 엔티티가 영속성 컨텍스트에서 분리될때, 부모엔티티와 자식엔티티도 별개로 분리된다(?)
ALL : 위를 모두 가져가는것
PERSIST만 추가하면되지만, 삭제까지 같이하면 좋으니까..
LEVEL7
@Query("SELECT c FROM Comment c JOIN c.user WHERE c.todo.id = :todoId")
List<Comment> findByTodoIdWithUser(@Param("todoId") Long todoId);
[Hibernate]
select
c1_0.id,
c1_0.contents,
c1_0.created_at,
c1_0.modified_at,
c1_0.todo_id,
c1_0.user_id
from
comments c1_0
where
c1_0.todo_id=?
2024-10-02T20:36:15.565+09:00 TRACE 38116 --- [nio-8080-exec-1] org.hibernate.orhttp://m.jdbc.bind : binding parameter (1:BIGINT) <- [1]
[Hibernate]
select
u1_0.id,
u1_0.created_at,
u1_0.email,
u1_0.modified_at,
u1_0.nickname,
u1_0.password,
u1_0.user_role
from
users u1_0
where
u1_0.id=?
2024-10-02T20:36:15.579+09:00 TRACE 38116 --- [nio-8080-exec-1] org.hibernate.orhttp://m.jdbc.bind : binding parameter (1:BIGINT) <- [8]
[Hibernate]
select
u1_0.id,
u1_0.created_at,
u1_0.email,
u1_0.modified_at,
u1_0.nickname,
u1_0.password,
u1_0.user_role
from
users u1_0
where
u1_0.id=?
첫번째 쿼리문을 제외한 아래 두 쿼리는
user를 찾는 쿼리가 나가는것을 볼 수 있다.
@Query("SELECT c FROM Comment c LEFT JOIN FETCH c.user WHERE c.todo.id = :todoId")
List<Comment> findByTodoIdWithUser(@Param("todoId") Long todoId);
[Hibernate]
select
c1_0.id,
c1_0.contents,
c1_0.created_at,
c1_0.modified_at,
c1_0.todo_id,
c1_0.user_id,
u1_0.id,
u1_0.created_at,
u1_0.email,
u1_0.modified_at,
u1_0.nickname,
u1_0.password,
u1_0.user_role
from
comments c1_0
left join
users u1_0
on u1_0.id=c1_0.user_id
where
c1_0.todo_id=?
쿼리문 하나로 바뀐것을 볼 수 있다
'TIL' 카테고리의 다른 글
20241007 본캠프 57일차 TIL (0) | 2024.10.07 |
---|---|
20241004 본캠프 56일차 TIL (0) | 2024.10.04 |
20241001 본캠프 54일차 TIL (1) | 2024.10.01 |
20240930 본캠프 53일차 TIL (0) | 2024.09.30 |
20240927 본캠프 52일차 TIL (0) | 2024.09.27 |