패스트 캠퍼스 JAVA 웹 프로그래밍 마스터 18일차(Docker, ViewResolver, profile, CTIP, ThreadLocal)
lalwr
...분 소요
- 운영
- 로컬서버
- 개발자 컴퓨터 - 로컬 DB
- 개발서버
- 개발 서버 - 개발 DB
- 운영서버
- 운영 서버 - 운영 DB
- maven profile, spring profile
- profile 설정
- Spring, Maven, Gradle
- 차이점은??
- CTIP
- 지속적인 통합, 지속적인 TEST, 지속적인 Build
- jenkins를 통해 GitHub에서 소스의 변경여부를 파악하고 테스트,빌드, report생성, error를 파악하고 사용자에게 mail, slack을 통해 통보할수 있으며 개발서버에 결과물(war, jar)파일을 deploy(배치)하며 서버를 재시작을 자동으로 해준다.
- Docker
- 개발환경 운영환경 같은 방법으로 관리할 수 있다.
- 운영체제의 자원을 사용한다.
- 설정파일만 있으면 어디서든 똑같은 환경으로 구성할 수 있다.
- 설치 (Docker compose도 포함되어 있다.)
- docker ps (목록)
- https://store.docker.com/editions/community/docker-ce-desktop-mac
- Reference architecture
- 로드밸런싱
- 이중화, 확장유연
- 대용량 서비스면 관계맺어야 할 테이블이 DB가 서로 다른곳에 있을 수 있다. 개발자가 버그에 대해 생각하고 롤백처리 해야한다.
- 분산 트랜잭션, 2단계 커밋등으로 처리할 수 있다.(서버를 사야한다. 비싸다.)
- DB와 많은 Connection을 맺고 있으면 문제가 생길수 있다. 그래서 이중화 NUIX(웹서버) ,WAS(REST API SERVER)를 DB와 연결하고 REST API 서버와 통신하게 만든 후 REST API SERVER와 통신을 통해 DB정보를 얻어온다.
- Connection pool
- DB와 연결을 미리 연결을 한 상태를 말한다. Datasource를 통해 연결한다.
- 샤딩(Sharding) 전략
- 나누기 전략 : DB가 늘어나면 마이그레이션 해야한다.
- 하나의 DB에서 특정한 카페의 데이터가 많을시에는 다른 카페의 속도가 느려질수 있으니 특정 카페만의 DB를 따로 구성하여 마이그레이션한다.
- Srping Boot 2.0
- redis
- rabbitmq
- JPA
- 언어 설정
- Locale
- I18N
- 지역화
- 하드코딩으로 적지말고 properties를 통해 사용해야 한다.
- ThreadLocal
- static한 객체 한테 thread별로 같은 쓰레드 안에서는 값을 유지해 준다.
- 파라미터로 넘기지않아도 값을 꺼낼 수 있다. 같은 쓰레드라면
- static이 아니면 매번 필드가 메모리에 만들어 진다.
- ThreadLocal을 사용하려면 static으로 사용한다.
- DispatcherServlet 내부 동작흐름 상세 -요청 선처리 작업
- 요청 -> Locale 결정(언어설정) -> RequestContextHolder에 요청 저장(ThreadLocal로 구성되어있음) -> FlashMap복원(Redirect) -> 멀티파트 요청(파일관련) -> 아니요 : 핸들러 결과와 실행 / 예 : MultipartResolver가 멀티파트 결졍 -> 핸들러 결과와 실행
- RequestContextHolder에는 HttpServletRequest등을 포함하고 있다.
- MultipartResolver가 작동할 떄 확장된 HttpServletRequest를 사용한다. 기존 HttpServletRequest 는 파일관련 작업을 지원하지 않는다.
- Redirect FlashMap
- FlashMap을 통해 값을 읽을 수 있다.
- 1번만 사용가능하다.
- 새로고침하면 사라진다.
- ViewResolver
- View객체에서 제일 중요한것은 render 메소드다.
- ViewResolver객체에서 제일 중요 한 것은 resolveViewName 메소드다.
- InternalResourceViewResolver는 내부적으로 JstlView 를 사용하고 forward 해준다.
- 사용자가 요청한 타입에 따라서 다른 결과를 보여주고 싶을때는 ContentNegotiationManager 를 사용한다.(pdf, json등)
@Bean
public ViewResolver contentNegotiatingViewResolver(ContentNegotiationManager contentNegotiationManager) {
ContentNegotiatingViewResolver resolver = new ContentNegotiatingViewResolver();
resolver.setContentNegotiationManager(contentNegotiationManager);
// Define all possible view resolvers
List resolvers = new ArrayList();
resolvers.add(new HtmlViewResolver());
resolvers.add(new JsonViewResolver()); // http://localhost:8080/guestbooks.json
resolver.setViewResolvers(resolvers);
return resolver;
}
@Bean
public ContentNegotiationManager contentNegotiationManager(){
ContentNegotiationManagerFactoryBean contentNegotiationManager = new ContentNegotiationManagerFactoryBean();
contentNegotiationManager.setFavorPathExtension(true);
contentNegotiationManager.setIgnoreAcceptHeader(true);
contentNegotiationManager.setUseJaf(false);
contentNegotiationManager.setDefaultContentType(MediaType.TEXT_HTML);
contentNegotiationManager.addMediaType("html", MediaType.TEXT_HTML);
contentNegotiationManager.addMediaType("json", MediaType.APPLICATION_JSON);
return contentNegotiationManager.getObject();
}
import org.springframework.web.servlet.View;
import org.springframework.web.servlet.ViewResolver;
import java.util.Locale;
public class JsonViewResolver implements ViewResolver {
@Override
public View resolveViewName(String s, Locale locale) throws Exception {
return new JsonView();
}
}
import org.springframework.web.servlet.View;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.util.Map;
public class JsonView implements View{
@Override
public String getContentType() {
return "application/json";
}
@Override
public void render(Map map, HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
httpServletResponse.setContentType("application/json");
PrintWriter out = httpServletResponse.getWriter();
out.println("{\"name\":\"urstory\"}");
}
}
import org.springframework.web.servlet.View;
import org.springframework.web.servlet.ViewResolver;
import java.util.Locale;
public class HtmlViewResolver implements ViewResolver {
@Override
public View resolveViewName(String s, Locale locale) throws Exception {
return new HtmlView();
}
}
import org.springframework.web.servlet.View;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.util.Map;
public class HtmlView implements View{
@Override
public String getContentType() {
return "text/html";
}
@Override
public void render(Map map, HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws Exception {
httpServletResponse.setContentType("text/html");
PrintWriter out = httpServletResponse.getWriter();
out.println("hello!!!");
}
}
이전글
...
다음글
...