Home
스프링 MVC 시작하기 - XML로 세팅하기
스프링 MVC 시작하기 - XML로 세팅하기 Web.xml 설정하기 root-context.xml 설정하기 servlet-context 설정하기 의존관계 설정하기<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.example</groupId> <artifactId>springMVCstep3</artifactId> <version>1.0-SNAPSHOT</version> <properties> <javax.servlet-version>4.0.1</javax.servlet-version> <javax.servlet.jsp-version>2.3.3</javax.servlet.jsp-version> <javax.servlet.jsp.jstl-version>1.2</javax.servlet.jsp.jstl-version> <org.springframework-version>5.2.2.RELEASE</org.springframework-version> <!-- <org.springframework-version>4.3.25.RELEASE</org.springframework-version> --> </properties> <!-- 라이브러리 셋팅 --> <dependencies> <!-- https://mvnrepository.com/artifact/javax.servlet/javax.servlet-api --> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>${javax.servlet-version}</version> <scope>provided</scope> </dependency> <!-- https://mvnrepository.com/artifact/javax.servlet.jsp/javax.servlet.jsp-api --> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>javax.servlet.jsp-api</artifactId> <version>${javax.servlet.jsp-version}</version> <scope>provided</scope> </dependency> <!-- https://mvnrepository.com/artifact/javax.servlet.jsp.jstl/jstl --> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> <version>${javax.servlet.jsp.jstl-version}</version> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${org.springframework-version}</version> </dependency> </dependencies> <build> <finalName>springMVCstep3</finalName> <sourceDirectory>src/main/java</sourceDirectory> <testSourceDirectory>src/test/java</testSourceDirectory> <pluginManagement> <plugins> <plugin> <artifactId>maven-compiler-plugin</artifactId> <version>3.8.0</version> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> <plugin> <artifactId>maven-war-plugin</artifactId> <version>3.2.1</version> <configuration> <warSourceDirectory>WebContent</warSourceDirectory> </configuration> </plugin> </plugins> </pluginManagement> </build> <!-- 라이브러리 버전관리 --></project> Web.xml 설정하기 톰캣 DispatcherServlet 을 스프링 DispatcherServlet 으로 바꾸기 Bean을 정의할 xml 파일을 정의하기 Listener 를 설정한다. 파라미터 인코더 를 설정한다. <!-- 현재 웹 애플리케이션에서 받아들이는 모든 요청에 대해 appServlet이라는 이름으로 정의되어 있는 서블릿을 사용하겠다. --><servlet-mapping> <servlet-name>appServlet</servlet-name> <url-pattern>/</url-pattern></servlet-mapping><!-- 요청 정보를 분석해서 컨트롤러를 선택하는 서블릿을 지정한다. --><servlet> <servlet-name>appServlet</servlet-name> <!-- Spring MVC에서 제공하고 있는 기본 서블릿을 지정한다. --> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <!-- Spring MVC 설정을 위한 xml 파일을 지정한다. --> <init-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/config/servlet-context.xml</param-value> </init-param> <load-on-startup>1</load-on-startup></servlet> <!-- Bean을 정의할 xml 파일을 지정한다. --><context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/config/root-context.xml</param-value></context-param> <!-- 리스너설정 --><listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></listener>
Spring Boot 게시판 만들기 21 - 젠킨스를 이용해 배포하기
21. 젠킨스를 이용해 배포하기플러그인 설치Jenkins 관리 > 플러그인 관리 Publish Over SSH를 설치해준다. 원격 서버 접속 설정하기
Spring Boot 게시판 만들기 20 - 프록시 서버 이용하기
20. 프록시 서버 이용하기현재는 client 가 Web Application에 접근하기 위해서는 8080포트를 사용해야 한다. client가 쉽게 접근 할 수 있도록 80번 포트로 어플리케이션을 띄어야 하는데 ubuntu에서는 일반 사용자가 80번 포트를 사용할 수 있는 권한이 없다. 만약 80번 포트로 프로그램을 실행하게 되면 아래와 같은 권한 오류가 뜨게 된다. 그렇다고 어플리케이션을 띄울 때 마다 매번 sudo권한으로 실행시킬 수도 없는 노릇이다. 맥에서는 80번 포트로 잘 열리는데 우분투에서 오류가 떠서 당황 했다. 우분투에서 1024미만 포트는 일반 사용자가 사용할 수 없는 포트이다. Caused by: java.net.SocketException: Permission denied at java.base/sun.nio.ch.Net.bind0(Native Method) ~[na:na] at java.base/sun.nio.ch.Net.bind(Net.java:455) ~[na:na] at java.base/sun.nio.ch.Net.bind(Net.java:447) ~[na:na] at java.base/sun.nio.ch.ServerSocketChannelImpl.bind(ServerSocketChannelImpl.java:227) ~[na:na] at java.base/sun.nio.ch.ServerSocketAdaptor.bind(ServerSocketAdaptor.java:80) ~[na:na] at org.apache.tomcat.util.net.NioEndpoint.initServerSocket(NioEndpoint.java:228) ~[tomcat-embed-core-9.0.41.jar!/:9.0.41] at org.apache.tomcat.util.net.NioEndpoint.bind(NioEndpoint.java:211) ~[tomcat-embed-core-9.0.41.jar!/:9.0.41] at org.apache.tomcat.util.net.AbstractEndpoint.bindWithCleanup(AbstractEndpoint.java:1159) ~[tomcat-embed-core-9.0.41.jar!/:9.0.41] at org.apache.tomcat.util.net.AbstractEndpoint.start(AbstractEndpoint.java:1245) ~[tomcat-embed-core-9.0.41.jar!/:9.0.41] at org.apache.coyote.AbstractProtocol.start(AbstractProtocol.java:603) ~[tomcat-embed-core-9.0.41.jar!/:9.0.41] at org.apache.catalina.connector.Connector.startInternal(Connector.java:1064) ~[tomcat-embed-core-9.0.41.jar!/:9.0.41] ... 29 common frames omitted nginx를 이용해 프록시 서버 만들어주기80번 포트를 사용하기 위해 Proxy 서버를 띄어 놓고 Proxy 서버로 요청이 들어오면 Spring Boot 프로그램으로 Forwarding 해주도록 설정을 할 것이다. sudo 명령어를 사용해 프로그램을 시키는 방법도 있지만, 매번하기에는 번거롭다는 단점도 있고 /etc/sudoers에 패스워드 권한을 풀어줄 수도 있지만 보안상의 문제가 있어서 가장 안전한 방법으로 Proxy 서버를 이용하기로 했다. nginx 설치하기
Spring Boot 게시판 만들기 19 - Build시 DB 연결 Bug Fix 및 Profile 설정
19. Build시 DB 연결 Bug Fix 및 Profile 설정Jenkins에서 build 오류Jenkins에서 Build를 진행하면 Test시 해당 오류가 발생하게 된다. Test를 진행하면서 DBConfigByYml 클래스내 필드를 Application-mysql.yml 를 이용해 채우게 되는데 Application-mysql.yml 파일이 Github에는 올라가 있지 않아 문제가 생기게 되는 것이다. > Task :testSampleBoardApplicationTests > contextLoads() FAILED java.lang.IllegalStateException at DefaultCacheAwareContextLoaderDelegate.java:132 Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException at ConstructorResolver.java:800 Caused by: org.springframework.beans.factory.BeanCreationException at AutowiredAnnotationBeanPostProcessor.java:405 Caused by: java.lang.IllegalArgumentException at PropertyPlaceholderHelper.java:1782021-02-24 16:17:02.458 INFO 1610 --- [extShutdownHook] o.s.s.concurrent.ThreadPoolTaskExecutor : Shutting down ExecutorService 'applicationTaskExecutor'17 tests completed, 1 failed> Task :test FAILEDFAILURE: Build failed with an exception.* What went wrong:Execution failed for task ':test'.> There were failing tests. See the report at: file:///var/jenkins_home/workspace/sample-board/build/reports/tests/test/index.html* Try:Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.* Get more help at https://help.gradle.orgBUILD FAILED in 53s7 actionable tasks: 7 executedBuild step 'Invoke Gradle script' changed build result to FAILUREBuild step 'Invoke Gradle script' marked build as failureFinished: FAILURE 여러개의 @PropertySource 사용하기첫번째로 해결한 방법은 @PropertySource를 두개 사용하여 test를 진행할 시에는 H2 database를 바라보게 하고 운영시에는 MySQL을 바라 볼 수 있게 설정 파일을 두게 만들어 사용했다. @PropertySource는 순서에 따라 아래 값이 이전 값을 덮어 쓰게 된다. DBConfigByYml.java @Configuration@PropertySource(value = "classpath:application-h2.yml", factory = YamlPropertySourceFactory.class, ignoreResourceNotFound = true)@PropertySource(value = "classpath:application-mysql.yml", factory = YamlPropertySourceFactory.class, ignoreResourceNotFound = true)public class DBConfigByYml { @Value("${spring.datasource.driver-class-name}") private String driverClassName; @Value("${spring.datasource.url}") private String url; @Value("${spring.datasource.username}") private String username; @Value("${spring.datasource.password}") private String password; @Bean public DataSource dataSource() { return DataSourceBuilder.create() .driverClassName(driverClassName) .url(url) .username(username) .password(password) .build(); }} 여러개의 PropertySource 묶기
Spring Boot 게시판 만들기 18 - 외부로부터 설정 받기(yml)
18. 외부로부터 설정 받기(yml)YamlPropertySourceFactory.java public class YamlPropertySourceFactory implements PropertySourceFactory { @Override public PropertySource<?> createPropertySource(String name, EncodedResource resource) throws IOException { Properties propertiesFromYaml = loadYamlIntoProperties(resource); String sourceName = name != null ? name : resource.getResource().getFilename(); return new PropertiesPropertySource(sourceName, propertiesFromYaml); } private Properties loadYamlIntoProperties(EncodedResource resource) throws FileNotFoundException { try { YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean(); factory.setResources(resource.getResource()); factory.afterPropertiesSet(); return factory.getObject(); } catch (IllegalStateException e) { // for ignoreResourceNotFound Throwable cause = e.getCause(); if (cause instanceof FileNotFoundException) { throw (FileNotFoundException) e.getCause(); } throw e; } }} DBConfigByYml.java @Configuration@PropertySource(value = "classpath:application-mysql.yml", factory = YamlPropertySourceFactory.class)public class DBConfigByYml { @Value("${spring.datasource.driver-class-name}") private String driverClassName; @Value("${spring.datasource.url}") private String url; @Value("${spring.datasource.username}") private String username; @Value("${spring.datasource.password}") private String password; @Bean public DataSource dataSource(){ return DataSourceBuilder.create() .driverClassName(driverClassName) .url(url) .username(username) .password(password) .build(); }}
Spring Boot 게시판 만들기 17 - 외부로부터 설정 받기(property)
17. 외부로부터 설정 받기(property)Github에 프로젝트를 올릴때 데이터 베이스 접속 연결과 같은 민감한 정보는 다른 사람이 열람해서는 안되는 정보라 형상관리에서 제외한 상태로 올리게 된다. .gitignore **/application-mysql.yml**/application-mysql.properties 데이터베이스 접속을 위한 properties 만들기application-mysql.properties spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driverspring.datasource.url=jdbc:mysql://localhost:3306/{테이블}serverTimezone=UTC&characterEncoding=UTF-8spring.datasource.username={Username}spring.datasource.password={Password} TransactionManagementConfigurer은 Spring에서 데티어베이스 연결을 지원한다. DBConfig.java
스프링 핵심 원리 이해 - 객체 지향 원리 적용
목차 Post not found: spring-boot/spring-core/basic/basic2 객체 지향 설계 5원칙 SOLID DIP 원칙 위반 - 추상화와 구체화 둘다 의존MemberServiceImpl 클래스는 MemberRepository 인터페이스를 의존하면서 구현 클래스인 MemoryMemberRepository도 의존하고 있다. public class MemberServiceImpl implements MemberService{ // MemberServiceImpl 클래스는 MemberRepository 인터페이스와 구현체인 MemoryMemberRepository 둘다 의존하고 있다. private final MemberRepository memberRepository = new MemoryMemberRepository(); @Override public void join(Member member) { memberRepository.save(member); } @Override public Member findMember(Long memberId) { return memberRepository.findById(memberId); }} OrderServiceImpl 클래스는 MemberRepository 인터페이스와 DiscountPolicy 인터페이스를 의존하면서 구현 클래스인 MemoryMemberRepository 와 RateDiscountPolicy 를 의존하고 있다. 추상화와 구체화 둘다 의존하는 문제가 있다.–> DIP 위반 DIP의 원칙을 지키기 위해 의존 class내에서 구현 클래스를 가져오는 부분을 삭제하게 되면 객체가 존재하지 않아서 nullPointException이 발생한다. public class OrderServiceImpl implements OrderService { // OrderServiceImpl 클래스는 MemberRepository 인터페이스와 구현체인 MemoryMemberRepository // DiscountPolicy 인터페이스와 구현체인 RateDiscountPolicy 를 의존하는 문제점이 있다. private final MemberRepository memberRepository = new MemoryMemberRepository(); private final DiscountPolicy discountPolicy = new RateDiscountPolicy(); @Override public Order createOrder(Long memberId, String itemName, int itemPrice) { Member member = memberRepository.findById(memberId); int discountPrice = discountPolicy.discount(member, itemPrice); return new Order(memberId, itemName, itemPrice, discountPrice); }}
Spring Boot - 독립적으로 실행 가능한 JAR
독립적으로 실행 가능한 JAR앱을 어딘가에 배포하거나 도커 이미지로 만들거나 하기 위해서는 jar패키지로 패키징한 후 jar파일을 실행하는게 유용하다. jar파일 생성mvn package mvn pakcage명령어를 통해 앱을 jar파일로 생성한다. jar파일이 생성됨을 확인할 수 있다. jar파일 안에는 앱을 실행하기 위한 의존성(library)들이 전부 다 포함되어 있다. jar 파일 실행java -jar springinit-1.0-SNAPSHOT.jar