Home

0

Spring MVC Request Life Cycle - Interceptor

목차 Spring MVC - ArgumentResolver Spring MVC Request Life Cycle - ViewResolver Spring MVC Request Life Cycle - HandlerAdapter Spring MVC Request Life Cycle - HandlerMapping Spring MVC Request Life Cycle - DispatcherServlet Spring MVC Request Life Cycle - Interceptor Spring MVC Request Life Cycle - Filter Interceptor 스프링 Interceptor 는 Handler(Controller) 호출 전, 후에 사용자 요청 및 응답을 가로채 특정 로직을 수행하는 역할을 한다. DispatcherServlet 이후에 동작한다. 스프링 Filter 처럼 Request, Response 객체를 다른 객체로 변경하는 것이 불가능 하다. Interceptor 는 Request, Response 객체를 넘겨주는 방식으로 진행하지 않고, boolean 값을 반환하는 형태로 로직 수행 Interceptor 인터페이스 preHandle Handler 호출 전에 실행된다. HttpServletRequest 객체를 이용해 preHandle 이 true 를 반환하면 다음으로 진행하고, false 면 진행하지 않는다. postHandle Handler 호출 후에 실행된다. afterCompletion View 가 렌더링 된 이후에 호출된다. public interface HandlerInterceptor { default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { return true; } default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception { } default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception { }}

0

Spring Boot - HttpSession 사용하기

목차 Spring Boot - HttpSession 사용하기 Spring Boot - 직접 Session Storage 구현하기 Spring Boot - Cookie 사용하기 Spring boot Session 사용하기 2 request.getSession(true) HttpSession 이 존재하면 HttpSession 을 반환하고 존재하지 않으면 새로운 Session 을 반환한다. request.getSession(false) HttpSession 이 존재하면 현재 HttpSession 을 반한하고 존재하지 않으면 null 을 반환한다. @PostMapping("/login")public String loginV3(@Valid @ModelAttribute LoginForm form, BindingResult bindingResult, HttpServletRequest request){ log.info("Request Params : {}", form); if(bindingResult.hasErrors()){ return "login/loginForm"; } Member loginMember = loginService.login(form.getLoginId(), form.getPassword()); if(loginMember == null){ bindingResult.reject("loginFail", "아이디 또는 비밀번호가 맞지 않습니다."); return "login/loginForm"; } // 로그인 설공 처리 TODO // 세션이 있으면 있는 세션 반환, 없으면 신규 세션을 생성 HttpSession session = request.getSession(); // 세션에 로그인 회원 정보를 보관 session.setAttribute(SessionConst.LOGIN_MEMBER, loginMember); return "redirect:/";} @PostMapping("/logout")public String logoutV3(HttpServletRequest request){ HttpSession session = request.getSession(false); if(session != null){ session.invalidate(); } return "redirect:/";} @GetMapping("/")public String homeLoginV3(HttpServletRequest request, Model model){ HttpSession session = request.getSession(false); if(session == null){ return "home"; } Member LoginMember = (Member) session.getAttribute(SessionConst.LOGIN_MEMBER); // 세션에 회원 데이터가 없으면 home if(LoginMember == null){ return "home"; } // 세션이 유지되 로그인으로 이동 model.addAttribute("member", LoginMember); return "loginHome";} 스프링에서 지원하는 Session 기능 사용하기@GetMapping("/")public String homeLoginV3Spring( @SessionAttribute(name = SessionConst.LOGIN_MEMBER, required = false) Member loginMember, Model model){ // 세션에 회원 데이터가 없으면 home if(loginMember == null){ return "home"; } // 세션이 유지되 로그인으로 이동 model.addAttribute("member", loginMember); return "loginHome";}

0

Spring Boot - 직접 Session Storage 구현하기

목차 Spring Boot - HttpSession 사용하기 Spring Boot - 직접 Session Storage 구현하기 Spring Boot - Cookie 사용하기 직접 만든 Session 사용하기@Componentpublic class SessionManager { public static final String SESSION_COOKIE_NAME = "mySessionId"; private Map<String, Object> sessionStore = new ConcurrentHashMap<>(); public void createSession(Object value, HttpServletResponse response){ // Session id를 상성하고 값을 Session에 저장 String sessionId = UUID.randomUUID().toString(); // Session Store 에 새로운 Session 정보를 저장한다. // Session 은 Key Value 형태로 데이터를 저장 sessionStore.put(sessionId, value); // 쿠키 생성 // Session Id 를 Cookie 에 넣어 전달한다. Cookie mySessionCookie = new Cookie(SESSION_COOKIE_NAME, sessionId); response.addCookie(mySessionCookie); } public Object getSession(HttpServletRequest request){ // Request 에서 Session Id 를 가져온다. Cookie sessionCookie = findCookie(request, SESSION_COOKIE_NAME); if(sessionCookie == null){ return null; } // Session Store 에 저장된 Session 정보를 가져온다. return sessionStore.get(sessionCookie.getValue()); } public void expire(HttpServletRequest request){ Cookie sessionCookie = findCookie(request, SESSION_COOKIE_NAME); if(sessionCookie != null){ sessionStore.remove(sessionCookie.getValue()); } } public Cookie findCookie(HttpServletRequest request, String cookieName){ if(request.getCookies() == null){ return null; } return Arrays.stream(request.getCookies()) .filter(cookie -> cookie.getName().equals(cookieName)) .findAny() .orElse(null); }} @PostMapping("/login")public String login(@Valid @ModelAttribute LoginForm form, BindingResult bindingResult, HttpServletResponse response){ log.info("Request Params : {}", form); if(bindingResult.hasErrors()){ return "login/loginForm"; } Member loginMember = loginService.login(form.getLoginId(), form.getPassword()); if(loginMember == null){ bindingResult.reject("loginFail", "아이디 또는 비밀번호가 맞지 않습니다."); return "login/loginForm"; } // 로그인 설공 처리 TODO // 쿠키 사용하기 // 쿠키에 시간 정보를 주지 않으면 세선 쿠(브라우저 종료시 모두 종료) Cookie cookie = new Cookie("memberId", String.valueOf(loginMember.getId())); response.addCookie(cookie); return "redirect:/";} Testclass SessionManagerTest { SessionManager sessionManager = new SessionManager(); @Test void SessionTest(){ // 세션 생성 MockHttpServletResponse response = new MockHttpServletResponse(); Member member = new Member(); sessionManager.createSession(member, response); // 요청에 응답 쿠키 저장 MockHttpServletRequest request = new MockHttpServletRequest(); request.setCookies(response.getCookies()); // 세션 조회 Object result = sessionManager.getSession(request); assertThat(result).isEqualTo(member); // 세션 만료 sessionManager.expire(request); Object expired = sessionManager.getSession(request); assertThat(expired).isNull(); }} @PostMapping("/login")public String loginV2(@Valid @ModelAttribute LoginForm form, BindingResult bindingResult, HttpServletResponse response){ log.info("Request Params : {}", form); if(bindingResult.hasErrors()){ return "login/loginForm"; } Member loginMember = loginService.login(form.getLoginId(), form.getPassword()); if(loginMember == null){ bindingResult.reject("loginFail", "아이디 또는 비밀번호가 맞지 않습니다."); return "login/loginForm"; } // 로그인 설공 처리 TODO // 세션 관리자를 통해 세션을 생성하고, 회원 데이터 보관 // 쿠키에 시간 정보를 주지 않으면 세션 쿠키(브라주어 종료시 모두 종료) sessionManager.createSession(loginMember, response); return "redirect:/";} @PostMapping("/logout")public String logoutV2(HttpServletRequest request){ sessionManager.expire(request); return "redirect:/";}

0

Spring Boot - Cookie 사용하기

목차 Spring Boot - HttpSession 사용하기 Spring Boot - 직접 Session Storage 구현하기 Spring Boot - Cookie 사용하기 쿠키 생성스프링에서 쿠키는 Cookie 를 이용해 쉽게 생성할 수 있습니다. 생성한 쿠키를 Client 로 전달하기 위해 컨트롤러 메소드 파라미터로 HttpServletResponse 객체를 추가한 후 HttpServletResponse 객체에 생성한 쿠키를 넣어줍니다. @GetMapping("/cookie/create")public ResponseEntity<String> helloCookie(HttpServletResponse httpServletResponse) { Cookie cookie = new Cookie("helloCookie", URLEncoder.encode("Hello world", StandardCharsets.UTF_8)); httpServletResponse.addCookie(cookie); return ResponseEntity.ok().body("Create Cookie");} 쿠키 생성 테스트@Testvoid CookieTest() throws Exception { ResultActions resultActions = mockMvc.perform(MockMvcRequestBuilders.get("/cookie/create")) .andExpect(status().isOk()) .andExpect(cookie().exists("helloCookie")) .andExpect(cookie().value("helloCookie", "Hello+world")) .andDo(print());} TestRestTemplate 을 이용해 어플리케이션에 대한 컨트롤러 테스트를 진행합니다. Client 로 전달된 쿠키는 Response Header 에서 확인할 수 있습니다. @LocalServerPortprivate int port;@Autowiredprivate TestRestTemplate restTemplate;@Testvoid helloCookie() { String url = "http://localhost:" + port + "/cookie/create"; // 테스트할 엔드포인트 URL // REST API 호출 ResponseEntity<String> response = restTemplate.getForEntity(url, String.class); // 응답 헤더에서 쿠키 정보 가져오기 HttpHeaders headers = response.getHeaders(); List<String> cookies = headers.get(HttpHeaders.SET_COOKIE); assertThat(response.getBody()).isEqualTo("Create Cookie"); assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK); for (String cookie : cookies) { System.out.println("cookie = " + cookie); assertThat(cookie.contains("helloCookie")).isTrue(); }}

0

백준 14592 - 연구소

백준 14592 - 연구소https://www.acmicpc.net/problem/14592 문제풀이해당 문제에서는 3가지 입력 N, M, 지도 모양이 주어진다. N : 세로 크기 M : 가로 크기 지도 정보 지도 내 상태는 3가지 상태가 존재한다. 0 : 빈칸 1 : 벽 2 : 바이러스 알고리즘 실행계획은 다음과 같이 진행한다. 벽을 세운다. 바이러스 확산 시킨다. 바이러스 영역을 확인한다.

0

백준 1158 - 요세푸스 문제

백준 1158 - 요세푸스 문제https://www.acmicpc.net/problem/1158 문제 풀이해당 문제에서는 두가지 입력 N, K가 주어진다. N : 사람 수 K : 원에서 사람이 제거되는 간격 N, K의 최대 5000 이므로, 최대 O(N^2)의 시간복잡도내에서 문제를 해결해야 한다. 전체 소스 코드import java.io.*;import java.util.*;public class Main { public static void main(String[] args) throws IOException { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); String[] arguments = br.readLine().split(" "); int N, K; N = Integer.parseInt(arguments[0]); K = Integer.parseInt(arguments[1]); List<Integer> list = new ArrayList<>(); for (int i = 0; i < N; i++) { list.add(i + 1); } int index = 0; StringBuilder sb = new StringBuilder(); sb.append("<"); // 사람을 간격에 맞게 하나씩 제거해준다. while (list.size() > 1) { index += K - 1; index %= list.size(); int removedValue = list.remove(index); sb.append(Integer.toString(removedValue)); sb.append(", "); } // 마지막 숫자를 제거한다. index += K - 1; index %= list.size(); int removedValue = list.remove(index); sb.append(Integer.toString(removedValue)); sb.append(">"); System.out.println(sb.toString()); br.close(); }}

0

Spring Boot - Resource 추상화

목차 Spring Boot - StreamingResponseBody Spring Boot - ResourceRegion Spring Boot - 파일 다운로드 서비스 구현하기 Spring Boot - 파일 업로드 서비스 구현하기 Spring Boot - Resource 추상화 Spring Boot - MultipartFile 에서 발생하는 예외 처리 Spring Boot - MultipartFile 를 이용한 파일 업로드 Spring Boot - Part 객체를 이용한 파일 업로드 Spring boot Resource 추상화https://docs.spring.io/spring-framework/docs/3.2.x/spring-framework-reference/html/resources.html Resource 는 java.net.URL 을 추상화 해 스프링 프레임워크에서 Low-Level에 있는 자원에 쉽게 접근할 수 있도록 지원한다 ClassPath를 기준으로 리소스를 가져오는 기능의 부재 ServletContext를 기준으로 상대 경로를 읽어오는 기능의 부재 Resource.java public interface Resource extends InputStreamSource { boolean exists(); URL getURL() throws IOException; URI getURI() throws IOException; File getFile() throws IOException; long contentLength() throws IOException; long lastModified() throws IOException; Resource createRelative(String relativePath) throws IOException; @Nullable String getFilename(); String getDescription(); default boolean isReadable() { return exists(); } default boolean isOpen() { return false; } default boolean isFile() { return false; } default ReadableByteChannel readableChannel() throws IOException { return Channels.newChannel(getInputStream()); }} Resource 구현체

0

Spring Boot - 파일 다운로드 서비스 구현하기

목차 Spring Boot - StreamingResponseBody Spring Boot - ResourceRegion Spring Boot - 파일 다운로드 서비스 구현하기 Spring Boot - 파일 업로드 서비스 구현하기 Spring Boot - Resource 추상화 Spring Boot - MultipartFile 에서 발생하는 예외 처리 Spring Boot - MultipartFile 를 이용한 파일 업로드 Spring Boot - Part 객체를 이용한 파일 업로드 파일 다운로드를 위한 HTTP 해더서버에 저장된 파일을 다운 받기 위해서는 Response 해더에 Content-Disposition 정보가 필요합니다. Content-Disposition 는 HTTP 프로토콜에서 사용되는 헤더로, 서버가 클라이언트에게 제공하는 콘텐츠가 브라우저에 표시될지 또는 다운로드할지, 그리고 다운로드될 경우 파일 이름은 무엇인지 등을 지정합니다. Content-Disposition 는 inline, attachment 두 가지 종류가 있습니다. Content-Disposition 값이 inline 면 콘텐츠가 브라우저에서 직접 표시됩니다. attachment 면 콘텐츠가 다운로드를 위한 파일로 제공됩니다. filename 속성을 이용하면 다운로드하기 위한 파일이름을 지정할 수 있습니다. // Content-Disposition 값이 inline 일 경우 브라우저에 직접 표시됩니다.Content-Disposition: inline// attachment 일 경우 리소스를 파일로 다운로드할 수 있습니다. filename 속성을 통해 파일 이름을 지정할 수 있습니다.Content-Disposition: attachment; filename="example.txt" 리소스 다운로드 서비스 구현리소스를 반환하는 Response 객체에 Content-Disposition 해더를 추가해줍니다.

0

[Spring Cloud] - 33. Order Kafka Producer

목차 [Spring Cloud] - 33. Order Kafka Producer [Spring Cloud] - 32. kafka-mariadb 연결 [Spring Cloud] - 31. Kafka Topic 적용 Order Kafka Producer@RestController@RequestMapping("/order-service/")@RequiredArgsConstructorpublic class OrderController { private final OrderService orderService; private final KafkaProducer kafkaProducer; private final OrderProducer orderProducer; @PostMapping(value = "/{userId}/orders") public ResponseEntity<ResponseOrder> createOrder(@PathVariable("userId") String userId, @RequestBody RequestOrder orderDetails){ ModelMapper modelMapper = new ModelMapper(); modelMapper.getConfiguration().setMatchingStrategy(MatchingStrategies.STRICT); OrderDto orderDto = modelMapper.map(orderDetails, OrderDto.class); orderDto.setUserId(userId); orderDto.setOrderId(UUID.randomUUID().toString()); orderDto.setTotalPrice(orderDetails.getQty() * orderDetails.getUnitPrice()); ResponseOrder returnValue = modelMapper.map(orderDto, ResponseOrder.class); kafkaProducer.send("example-order-topic", orderDto); orderProducer.send("orders", orderDto); return ResponseEntity.status(HttpStatus.CREATED).body(returnValue); } @GetMapping(value = "/{userId}/orders") public ResponseEntity<List<ResponseOrder>> getOrder(@PathVariable("userId") String userId){ Iterable<OrderEntity> orderList = orderService.getOrdersByUserId(userId); List<ResponseOrder> result = new ArrayList<>(); orderList.forEach(v -> { result.add(new ModelMapper().map(v, ResponseOrder.class)); }); return ResponseEntity.status(HttpStatus.OK).body(result); }} @Service@Slf4j@RequiredArgsConstructorpublic class OrderProducer { private final KafkaTemplate<String, String> kafkaTemplate; public OrderDto send(String topic, OrderDto orderDto){ ObjectMapper mapper = new ObjectMapper(); String jsonInString = ""; try{ jsonInString = mapper.writeValueAsString(orderDto); }catch (JsonProcessingException ex){ ex.printStackTrace(); } kafkaTemplate.send(topic, jsonInString); log.info("Kafka Producer sent data from the Order microservice: " + orderDto); return orderDto; }} @Data@Builderpublic class Scheme { private String type; private List<Field> fields; private boolean optional; private String name;} @Data@AllArgsConstructorpublic class Field { private String type; private boolean optional; private String field;} @Data@Builderpublic class Payload { private String order_id; private String user_id; private String product_id; private int qty; private int unit_price; private int total_price;} @Data@AllArgsConstructorpublic class KafkaOrderDto implements Serializable { private Scheme scheme; private Payload payload;}

0

[Spring Cloud] - 32. kafka-mariadb 연결

목차 [Spring Cloud] - 33. Order Kafka Producer [Spring Cloud] - 32. kafka-mariadb 연결 [Spring Cloud] - 31. Kafka Topic 적용 Config// https://mvnrepository.com/artifact/org.mariadb.jdbc/mariadb-java-clientimplementation 'org.mariadb.jdbc:mariadb-java-client' create table users( id int auto_increment primary key, user_id varchar(20), pwd varchar(20), name varchar(20), created_at datetime default NOW()); Kafka Connect 설치curl -O http://packages.confluent.io/archive/5.5/confluent-community-5.5.2-2.12.tar.gz curl -O http://packages.confluent.io/archive/6.1/confluent-community-6.1.0.tar.gz tar xvf confluent-community-6.1.0.tar.gz