-
Notifications
You must be signed in to change notification settings - Fork 4
#30 웹소켓을 이용한 1:1 채팅 구현 #32
base: feature/29
Are you sure you want to change the base?
Conversation
- WebSocket 의존성 추가 - WebSocketConfig 추가 - json 의존성 추가 - SocketHandler class 추가 - Chatting Controller 추가
- 채팅 jsp 처리를 위한 servlet추가 - ModelAndView 사용 및 chat.jsp 추가 - spring.mvc.view 설정
- json-simple 의존성 추가 - sessionID값을 기준으로 채팅 상대방과 분리되게 JSP 변경 - 채팅 message jsonToObjectParser 함수로 파싱 되게 변경
- WebSocketHandlerRegistry에 방번호까지 등록 - 채팅방 생성, 이동, 정보 가져오는 method controller에 생성 - 메세지 전송 method에서 세션정보를 갖는 List를 이용해 해당 방에만 유효한 세션을 골라 발송하게 변경 - 방 생성 또는 참여 웹소켓 연결시 방의 인원을 조사후 방번호와 세션을 추가한다. - 방 퇴장 웹소켓 종료시 해당 세션을 삭제한다. - 채팅방, 방입장 jsp 작성
- messageType이 BinaryMessage인 데이터 디렉터리에 저장 및 발송 - chat.jsp에 웹소켓을 통해 fileSend함수 생성
이 부분은 멘토링시에 말씀드린 내용대로 전체 재검토 부탁드려요~ |
- RequestMapping 으로 되어있던 api를 http method에 맞게 변경 - api에 맞는 uri 패턴으로 변경 - uri 패턴 변경에 따른 room.jsp 변경 - SoketHandler.java 파일에 필요없는 변수 삭제 및 Thread-Safe하기 위해 전역변수를 지역변수로 변경
- WebSocketConfig 클래스 관련 주석 추가 - ChattingController에 REST URI 규약 적용 - roomDTO builder 패턴을 이용한 생성되게 변경 - ChattingResponse, ChattingRequest 생성 - SocketHandler에 예외발생시 로그파일로 만들게 변경 - ChattingMapper, ChattingService, ChattingMapper 클래스 생성을통한 채팅방 등록 및 찾기 구현 - room.jsp 에 uri 패턴 적용에 따른 변경
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
전체적으로 확인 다시 해주시고 리팩토링 해주세요~
@Bean | ||
public TaskScheduler taskScheduler() { | ||
ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler(); | ||
taskScheduler.setPoolSize(10); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
나중에 가면 이 사이즈도 조절해야할 수 있습니다. 기억만 해주시고 이 사이즈를 바꾸면 어떤 영향이 있는지 확인해주세요~
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
poolsize가 커지면 그만큼 서버입장에서 메모리를 많이 필요로 합니다.
pool 모두를 사용하고 있다면 다음 테스크 스케줄러에 등록된 쓰레드 데이터 처리시 지연이 발생합니다.
한 테스크 스케줄이 pool을 반환해야 처리됩니다. 다시말해 순차적으로 처리합니다.
추가로 머신의 cpu갯수와 같은 최대 스레드 수만 등록할수 있습니다.
|
||
static int roomNumber = 0; | ||
private ChattingResponse chattingResponse; | ||
List<RoomDTO> roomDTOList = new ArrayList<RoomDTO>(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이런쪽은 계속 수정해주세요~
* @return | ||
*/ | ||
@GetMapping("/waiting-room") | ||
public ModelAndView room() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
굳이 뷰는 필요 없어보입니다~
mv.addObject("roomName", params.get("roomName")); | ||
mv.addObject("roomNumber", params.get("roomNumber")); | ||
mv.setViewName("chat"); | ||
}else { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
컨벤션도 맞춰주세요
public class SocketHandler extends TextWebSocketHandler { | ||
|
||
private List<HashMap<String, Object>> rls = new ArrayList<>(); //웹소켓 세션을 담아둘 리스트 ---roomListSessions | ||
private static final String FILE_UPLOAD_PATH = "C:/usedMarketServer/attachFile/"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이렇게 하면 서버에 배포되었을때 동작할까요?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
상대경로로 파일명을 DownLoad하게 변경하겠습니다.
try { | ||
wss.sendMessage(new TextMessage(obj.toJSONString())); | ||
} catch (IOException e) { | ||
e.printStackTrace(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이거는 의도하신 코드인가요?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
알맞은 로그파일로 쓰게 변경하겠습니다.
- ChattingController에 chattingService 주입되게 변경 - roomDTOList를 DB에 저장한 데이터를 가져오게 변경
List<RoomDTO> roomDTOList = new ArrayList<RoomDTO>(); | ||
private final ChattingService chattingService; | ||
|
||
@Autowired |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
생성자주입시에 이 어노테이션이 필요할까요?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
생성자 주입시 단일 생성자(생성자가 2개 미만)인 경우에는 @Autowired 어노테이션 붙이지 않아도 주입됩니다.
@@ -63,8 +72,9 @@ public ModelAndView room() { | |||
* @return | |||
*/ | |||
@GetMapping("/rooms") | |||
public @ResponseBody List<RoomDTO> getRoom(@RequestParam HashMap<Object, Object> params){ | |||
return roomDTOList; | |||
public @ResponseBody |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ResponseBody
는 보통 메소드 위에 선언합니다. 이것도 컨벤션을 지키지 않은 것 같네요~
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
변경하겠습니다.
public @ResponseBody List<RoomDTO> getRoom(@RequestParam HashMap<Object, Object> params){ | ||
return roomDTOList; | ||
public @ResponseBody | ||
List<RoomDTO> getRoom(@RequestParam HashMap<Object, Object> params, @RequestBody RoomDTO roomDTO) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
파라미터를 Map
타입으로 받으면 단점이 뭐가 있을까요?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
현재 사용하지 않는 Key에 대해서 미리 Memory를 할당받아 사용하고 있는 단점이 있습니다.
load factor (key/메모리 size) 값을 넉넉히 할당받지 않으면 다시말해
load factor > 1 인 경우에는 Hash Collision이 발생합니다.
해결법으로는
Bucket Size를 단순히 2배로 늘린 후 Key값을 재배열합니다. 또는
충돌이 발생한 경우에 일정 Offset 간격으로 Bucket으로 접근하여 Search, Insert를 진행합니다.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
유지보수성에서는 문제가 없을까요?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
개발한 사람 이외의 사람들이 판단하기 어려운 점이 있습니다.
스프링에서는 커맨드 객체(Command Object)를 지원하여 HTTP에서 들어오는 각 속성 값들을
자동적으로 커맨드 객체에 바인딩하여 처리할 수 있게 변경가능합니다.
따라서 커맨드 객체(RoomDTO)를 이용하여@RequestMapping
이나 getParameter로 처리하지
않아도 쉽게 처리 되게 커맨드 객체를 인자로 설정하겠습니다.
그에따라 훨씬 코드 양도 줄고, 가독성도 좋아지고 간편해집니다.
참고 https://engkimbs.tistory.com/693
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
유지보수성 측면에서 코드 가 명시적으로 보이기 위해
파라미터를 DTO형으로 변경하였습니다.
@@ -77,7 +87,7 @@ public ModelAndView moveRoom(@RequestParam HashMap<Object, Object> params) { | |||
ModelAndView mv = new ModelAndView(); | |||
int roomNumber = Integer.parseInt((String) params.get("roomNumber")); | |||
|
|||
List<RoomDTO> new_list = roomDTOList.stream().filter(o->o.getRoomNumber()==roomNumber).collect(Collectors.toList()); | |||
List<RoomDTO> new_list = chattingService.getRooms(null).stream().filter(o->o.getRoomNumber()==roomNumber).collect(Collectors.toList()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
chattingService.getRooms(null)
라는 시그니쳐를 보면 어떤 값이 리턴될지 예상이 가시나요?
차라리 getAllRooms()
를 선언하시는게 나을 것 같습니다
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
변경했습니다.
`roomName`, | ||
`type` | ||
FROM `room` | ||
LIMIT 100 OFFSET 0 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OFFSET
을 굳이 써주신 이유가 있으신가요? 그리고 이 쿼리는 딱 고정된 값만 가져올 것 같네요
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
추후에 읽은 채팅방은 표시되지 않게 하려고헀습니다.
고정값을 안쓰게 변경했습니다.
</select> | ||
|
||
<!-- <select id="selectRooms" resultType="com.market.server.dto.RoomDTO">--> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
주석은 올리지 않는게 좋습니다~ 차라리 지우고 올려주세요. 머지되는 코드는 최대한 완벽한 코드여야합니다. 이 피드백도 여러 번 드리는 것 같네요~
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
변경했습니다.
- application dev, release 버전 나누기 - Rooms정보 가져올시 order by 정보와 limit, offset 설정 파라미터 추가 - getLastRoomNumber 함수 추가 - ChattingController 쓰지않는 파라미터, 변수 제거
- 메소드명 명시적으로 변경 getRooms -> getAllRooms - 채팅중 파일 다운로드 디렉토리를 상대적으로 변경, 파일명은 처리 시간으로 변경 - 예외처리시 e.printStackTrace(); 부분을 log.error파일에 기록 - @responsebody 메소드 위로 수정 - taskScheduler 메소드 주석 추가
- gitignore에 attachFile 폴더 추가
@@ -51,10 +42,11 @@ public ModelAndView room() { | |||
*/ | |||
@PostMapping("/rooms") | |||
public @ResponseBody | |||
List<RoomDTO> createRoom(@RequestParam HashMap<Object, Object> params, ChattingRequest chattingRequest) { | |||
List<RoomDTO> createRoom(@RequestParam HashMap<String, String> params) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
유지보수성 측면에서 Map을 쓰는게 좋을지 고민해주세요~
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
유지보수성 측면에서 코드 가 명시적으로 보이기 위해
파라미터를 DTO형으로 변경하였습니다.
File dir = new File(FILE_UPLOAD_PATH); | ||
|
||
String fileName = new SimpleDateFormat("yyyyMMddHHmm'.jpg'").format(new Date()); | ||
File file = new File(""); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
안의 빈 문자열은 무슨 의미일까요?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
의미없는 생성으로 System.getProperty("user.dir") 으로 대체하겠습니다.
String fileName = "temp.jpg"; | ||
File dir = new File(FILE_UPLOAD_PATH); | ||
|
||
String fileName = new SimpleDateFormat("yyyyMMddHHmm'.jpg'").format(new Date()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
전역 변수로 만들어놓고 돌려쓸 수 있지 않을까요? 혹은 날짜포맷 유틸로도 분리가 가능할것같네요.
대신 SimpleDateFormat
는 전역변수로 쓰지 못할 것 같습니다. 왜 그럴까요?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Synchronization
Date formats are not synchronized. It is recommended to create separate format instances for each thread. If multiple threads access a format concurrently, it must be synchronized externally.
SimpleDateFormat 인스턴스는 필요한 경우 전역 상수로 선언 할 수 있지만
이 클래스는 스레드로부터 안전하지 않습니다. 여러 스레드가 동시에 액세스하는 경우 동기화해야합니다.
jdk 1.8 doc 참고
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
그럼 더 효율좋은 코드로 바꿔주세요~
|
||
String fileName = new SimpleDateFormat("yyyyMMddHHmm'.jpg'").format(new Date()); | ||
File file = new File(""); | ||
String fileDirectoryName = file.getAbsolutePath()+"\\usedMarketServer\\attachFile\\"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이렇게 하드코딩해도 될까요? 그리고 \\
는 리눅스에서는 /
가 될 것 같은데 어떻게 해야할까요?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
File.separator 로 변경하였습니다.
@@ -81,7 +88,7 @@ public void handleBinaryMessage(WebSocketSession session, BinaryMessage message) | |||
byteBuffer.compact(); //파일을 복사한다. | |||
outChannel.write(byteBuffer); //파일을 쓴다. | |||
}catch(Exception e) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
여기도 컨벤션이 안지켜져 있네요~
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
변경했습니다.
@@ -91,7 +98,7 @@ public void handleBinaryMessage(WebSocketSession session, BinaryMessage message) | |||
outChannel.close(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
try-with-resource 를 쓰면 어떨까요?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
변경했습니다.
- Api 인자에 HashMap 형태를 DTO 타입으로 변경 - getLastRoomNumber 메소드에 NULL이 올수 있어서 예외처리, 반환 타입을 INT -> Interger로 변경 - spring배너 title 변경
- 무의미한 File 생성 제거 - System.getProperty("user.dir"), File.separator 를 이용한 프로젝트 상대경로 설정 - 첨부파일 경로 gitignore 추가
- DateUtil 생성 yyyyMMddHHmm 형태 문자열 반환, 확인 메서드 - FileOutputStream, FileChannel 사용시 try-with-resource 적용
if (roomName != null && !roomName.trim().equals("")) { | ||
int roomNumber = chattingService.getLastRoomNumber(); | ||
roomDTO = RoomDTO.builder() | ||
int roomNumber = 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
아래에서 아무 조건없이 바로 할당하는데 여기에 0을 할당하신 이유가 있으신가요?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
변경하겠습니다.
public List<RoomDTO> createRoom(@RequestParam HashMap<String, String> params) { | ||
String roomName = (String) params.get("roomName"); | ||
RoomDTO roomDTO = null; | ||
public List<RoomDTO> createRoom(RoomDTO roomDTO, Model model) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
model을 꼭 쓸 필요가 있을까요?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Controller에서 생성한 데이터를 담아서 View로 전달할 때 사용하는 객체로 roomDTO에 정보가 다있어서
삭제하겠습니다.
public int getLastRoomNumber() { | ||
return chattingMapper.getLastRoomNumber(); | ||
public Integer getLastRoomNumber() { | ||
Integer result = -2; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이거도 코드가 이상합니다~
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
변경하겠습니다.
@@ -28,14 +28,18 @@ public void register(RoomDTO roomDTO) { | |||
public List<RoomDTO> getAllRooms(RoomDTO roomDTO) { | |||
List<RoomDTO> roomDTOList = null; | |||
if (roomDTO == null) | |||
roomDTOList = chattingMapper.selectRooms("NEWEST", 20, 0); | |||
roomDTOList = chattingMapper.selectRooms("NEWEST", 30, 0); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이런 값은 하드코딩보다는 config로 뺄 수 있지 않을까요?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ChattingService에 상수로 정의하겠습니다.
String roomNumber = (String) rls.get(i).get("roomNumber"); //세션리스트의 저장된 방번호를 가져와서 | ||
if(roomNumber.equals(rN)) { //같은값의 방이 존재한다면 | ||
if (roomNumber.equals(rN)) { //같은값의 방이 존재한다면 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
roomNumber
가 null일 수도 있을까요?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
roomNumber는 pk로 null일수 없습니다.
log.error("파일 write 실패" , e); | ||
}finally { | ||
} catch (Exception e) { | ||
log.error("파일 write 실패", e); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
로그만 찍고 아무 행위도 안하는게 의도하신게 맞을까요? 실패하면 실패했다고 알려줘야하지 않을까요?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IOException printStackTrace(); 추가했습니다.
FileOutputStream out = null; | ||
FileChannel outChannel = null; | ||
try { | ||
try (FileOutputStream out = new FileOutputStream(file, true); //생성을 위해 OutputStream을 연다. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
여기도 괄호 뒤에 개행 한번 넣어주시면 가독성에 좋을 것 같습니다
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
변경했습니다.
* @author topojs8 | ||
*/ | ||
public static String getNowTimeToyyyyMMddHHmm(Date date, String fileType) { | ||
return new SimpleDateFormat("yyyyMMddHHmm").format(date) + fileType; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이것도 결국 새로운 객체를 사용하는건 마찬가지같네요. 객체를 계속 생성하지 않을 수 있는 방법이 있지 않을까요?
이런 작아보이는 것들도 쌓여서 좋은 코드를 이루는 겁니다. 작은것도 도큐먼트를 꼼꼼히 읽어보고 다른게 뭐가 있을지 계속 찾아보시면서 개선해주세요~
Date date = simpleDateFormat.parse(dateStr); | ||
System.out.println("Successfully Parsed Date " + date); | ||
} catch (ParseException e) { | ||
System.out.println("ParseError " + e.getMessage()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
System.out.println
에 대한 것을 책에서 읽으신 것 같은데 코드에 반영이 안돼있네요.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
변경했습니다.
} catch (ParseException e) { | ||
System.out.println("ParseError " + e.getMessage()); | ||
} catch (Exception e) { | ||
e.printStackTrace(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
여기도 마찬가지입니다
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
변경했습니다.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
변경이 안되어있네요
리뷰를 하면서 느끼는게 리뷰에 나온 내용에 대해 알아보고 익히는게 아니라 그때그때 리뷰 내용을 반영하기만 하는 느낌입니다. |
|
- 파일명 생성하는 DateFormat을 ThreadLocal을 사용하여 재사용하게 변경 - ChattingService에 채팅목록 검색시 Default설정 상수화 - SocketHandler에 파일 인덱스, 파일 디렉토리명 상수화, 예외처리 에러 추가 - ChattingController 필요없는 로컬변수, model 파라미터 제거
|
) { | ||
byteBuffer.flip(); //byteBuffer를 읽기 위해 세팅 | ||
byteBuffer.compact(); //파일을 복사한다. | ||
outChannel.write(byteBuffer); //파일을 쓴다. | ||
} catch (Exception e) { | ||
} catch (IOException e) { | ||
e.printStackTrace(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
여기도 쓰면 안돼는 메소드를 쓰셨네요
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- e.getMessage(), e.toString()
- 에러 메세지만 간략하게 보여준다.
- 두 개의 차이점은 그냥 java exception이냐 보여주는 차이. 찍어보면 알 수 있다.
- e.printStackTrace()
- 모두가 아는.. 처음 호출한데서부터 에러 발생한 끝까지 들어간 내용 그대로 보여준다. 말 그대로 보면, stack을 trace 했으니. 처음 호출에서부터 차곡차곡 쌓인 모든 함수들을 그대로 뿌려준다.
e.getMessage(), e.toString() 를 사용해도 될까요??
public static final String getNowTimeToyyyyMMddHHmm(Date date, String fileType) { | ||
SimpleDateFormat sdf = tl.get(); | ||
if(sdf == null) { | ||
sdf = new SimpleDateFormat("yyyyMMddHHmm"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- 있는지 검사하고
- 없으면 새로 생성한다
이거는 thread safe 한가요? 그리고 스레드로컬 사용법에 대해 잘못 이해하고 계신듯 하네요~
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
로컬변수여서 thread safe한 줄 알고 있는데 아닐까요??
@@ -28,9 +37,10 @@ private static void parseDate(String dateStr) { | |||
try { | |||
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMddHHmm"); | |||
Date date = simpleDateFormat.parse(dateStr); | |||
log.info("Successfully Parsed Date " + date); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
로그 포맷팅을 사용해주세요
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
변경했습니다.
} catch (ParseException e) { | ||
System.out.println("ParseError " + e.getMessage()); | ||
} catch (Exception e) { | ||
e.printStackTrace(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
변경이 안되어있네요
- System.out.println문 삭제 - Exception 문 삭제 - ThreadLocal문 변경 - 메인 어플리케이션 명 변경
@@ -37,12 +37,9 @@ private static void parseDate(String dateStr) { | |||
try { | |||
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyyMMddHHmm"); | |||
Date date = simpleDateFormat.parse(dateStr); | |||
log.info("Successfully Parsed Date " + date); | |||
System.out.println("Successfully Parsed Date " + date); | |||
log.info("Successfully Parsed Date " , date); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이건 굳이 찍어야할 로그일까요? 불필요한 로그를 계속 찍으면 분석할 의미가 없는 로그가 엄청 늘어나게 됩니다
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
삭제하였습니다.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
전체적으로 다시 돌아보니 리뷰를 드렸음에도 리뷰를 드린 곳에만 반영이 되고 다른 곳에는 기존에 공부했던 내용들이 반영되지 않은 경우가 많네요. 그리고 기본적인 카멜케이스 같은 것조차 지켜지지 않은 곳이 있어 리뷰의 의미가 없어보여서 리뷰를 중단하고 기존에 남기던 것 몇개만 남깁니다.
코드리뷰는 당장의 코드의 허술함만 땜질하는 것뿐이 아니라 지식을 습득하여 미래에 더 나은 코드를 짜기 위한 목적도 있습니다. 그리고 그 지식을 습득할 수 있는 레퍼런스도 드렸었고요.
지금 이 PR은 아무 코드나 가져온 다음 리뷰만 적용해서 당장 포트폴리오로 쓸만한 적절하게 그럴듯해보이는 코드를 만들려는 목적으로 보이기도 합니다. 계속 말씀드리는 것이지만 단순하게 웹소켓을 썼다라는 것만으로는 원하시는 기업의 다른 면접들에 가서도 커버를 못칠겁니다.
여태까지 습득한 지식들이 코드에 녹아있어야하는데 여기 작성된 코드들을 보면 여태까지 진행한 멘토링 몇 개월동안 공부한게 물거품으로 보일 정도로 너무 허술합니다. 17개밖에 안돼는 파일에서 리뷰를 조금 더 달면 100개를 돌파할 것 같고요.
추후 멘토링을 그만하시더라도 꼭 이해해두셔야하는 것은 단순히 "~ 기술을 사용해봤다", "~를 경험했다"만으로는 어필이 안됩니다. 얼마나 "잘" 사용하려했는지가 중요한데 여기는 기본적인 자바코드부터가 "잘" 사용되고 있지 않네요.
클라우드 제품 사용 경험을 위해 무료크레딧이 제공되는 애저나 네이버클라우드를 권했었을때도 별다른 이유나 코멘트 없이 AWS를 사용하시기도 했고, 블로그글 작성 때도 문제가 있었죠. 물론 제가 말씀드린 내용이 합리적이지 않다고 판단하셨을수도 있지만 그렇다면 합리적이지 않은 이유를 들며 더 합리적인 방향으로 가기 위해 커뮤니케이션을 시도하셨어야합니다.
어느정도 경력이 있는 사람은 개발습관과 생각이 박혀버려서 그걸 바꾸기가 쉽지 않습니다. 그 한계를 벗어나셔야 개발자로써 한걸음 더 나아가실 수 있을 것 같네요.
앞으로 어떻게 할지는 고민을 좀 해보고 추후에 얘기를 좀 나눠보면 좋겠네요
@@ -17,6 +17,7 @@ market.server.redis.password= | |||
# expire | |||
# millisecond 600����� �� 10�ð� |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
뭔가 글자가 깨진것 같네요
@@ -17,6 +17,7 @@ market.server.redis.password= | |||
# expire | |||
# millisecond 600����� �� 10�ð� | |||
expire.defaultTime=36288000 | |||
expire.products=5 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이거는 밀리초인가요?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
5000으로 변경했습니다.
@@ -1,5 +1,5 @@ | |||
# Server | |||
server.port=8888 | |||
server.port=9000 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이제는 로컬용 포트변경코드는 지우는게 낫지 않을까요?
String roomName = roomDTO.getRoomName(); | ||
RoomDTO room = null; | ||
|
||
if (roomName != null && !roomName.trim().equals("")) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
roomName
이 null이면 NPE가 날 것 같네요
RoomDTO room = null; | ||
|
||
if (roomName != null && !roomName.trim().equals("")) { | ||
int roomNumber = chattingService.getLastRoomNumber(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이것도 동시성문제가 있어보이네요. 이 메소드는 호출할때마다 다른값을 반환하나요? 혹은 같은 값을 반환할수도 있나요?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
RoomDTO가 정상적으로 등록되지 않았다면 같은값을 반환할 수도 있습니다.
ModelAndView mv = new ModelAndView(); | ||
int roomNumber = roomDTO.getRoomNumber(); | ||
|
||
List<RoomDTO> new_list = chattingService.getAllRooms(null).stream().filter(o -> o.getRoomNumber() == roomNumber).collect(Collectors.toList()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
여기는 카멜케이스가 지켜지지 않았네요
- createRoom NPE 구문 추가 - createRoom convention 적용 - 로컬포트 삭제 - expire.products=5000 5초로 변경
우선 목요일 코딩테스트, 금요일 과제 이후에 |
No description provided.