수업이 끝나면서 각 과목 별 시험 쳤던 문제들을 복습 겸 정리해보겠습니다. 첫 번째 글은 제일 처음 수업을 들었던 순서대로 자바 과목 문제가 되겠네요.
[애플리케이션테스트수행하기]
1. 아래 클래스를 컴파일하고 실행하여 결과를 출력하고자 한다.
class Hello{
public static void main(String[] args){
System.out.println("Java World");
}
}
1) 컴파일 실행문 : javac Hello.java
2) 실행 명령문 : java Hello
3) 실행결과 : Java World
2. 위 코드의 파일명을 적으시오.
Hello.java
[ 3~5 ] 다음 클래스에 대해 물음에 답하시오.
class A {
private int a;
public void setA(int a){ this.a = a; }
}
class B extends A {
protected int b, c;
}
class C extends B {
public int d, e;
}
3. A obj A = new A(); 에 의해 생성되는 객체 objA의 멤버들을 모두 나열하라.
2개 private int a; public void setA( int a ) { this.a=a; }
4. B obj B = new B(); 에 의해 생성되는 객체 objB의 멤버들을 모두 나열하라.
4개 private int a; public void setA( int a ) { this.a=a; } protected int b, c;
5. C obj C = new C(); 에 의해 생성되는 객체 objB의 멤버들을 모두 나열하라.
6개 private int a; public void setA( int a ) { this.a=a; } public int d, e;
6. 자바의 모든 클래스가 반드시 상속받게 되어있는 클래스는? 1
1) Object 2) Java 3) Class 4) Super
7. 다음 중 설명에 적절한 단어를 기입하라.
자바에서 상속받는 클래스를 ( sub class ) 라고 부르며, extends 키워드를 이용하여 상속을 선언한다. 상속받은 클래스에서 상속해준 부모 클래스의 멤버를 접근할 때 ( super ) 키워드를 이용한다. 한편 자바의 클래스는 객체를 만들 수 없는 추상클래스와 인터페이스가 있다. 인터페이스는 자바 클래스와 달리 ( 다중상속 ) 을 할 수 있으며 ( implements ) 키워드를 이용하여 인터페이스를 구현한 클래스를 작성한다.
[애플리케이션결함조치하기]
8. 다음 코드에서 생성자로 인한 오류를 찾아내어 이유를 설명하고 오류를 수정하라.
class A {
private int a;
protected A(int a) { this.a = a; }
}
class B extends A {
private int b;
protected B() { b = 0; }
}
해설 >> 클래스 A의 생성자를 protected로 사용해도 무관하므로 다음은 오류가 아니다.
protected A (int a) { this.a=a; }
잘못된 부분은 클래스 B의 다음 생성자에 있다. class A 에서 디폴트 생성자를 선언하거나 class B의 생성자에서 super(b)를 선언해야 한다.
protected B () { b=0; }
9. 추상 클래스를 구현하는 문제이다. 실행 결과와 같이 출력되도록 클래스 B를 완성하라.
abstract class OddDetector {
protected int n;
public OddDetector (int n) {
this.n = n;
}
public abstract boolean isOdd(); //홀수이면 true 리턴
}
public class B extends OddDetector {
public B(int n) {
super(n);
}
public static void main (String[] args) {
B b = new B(10);
System.out.println(b.isOdd()); //B가 짝수이므로 false 출력
}
}
10. 다음 코드의 실행 결과 "반지름=10"이 출력되도록 Circle 클래스를 수정하라.
Circle c = new Circle(10);
c.paint();
답 >>
class Circle {
private int radius;
public Circle(int radius) {
this.radius = radius;
}
public void paint(){
System.out.printlnt("반지름 = " + radius);
}
}
[애플리케이션테스트수행하기]
[ 11~12 ] JUnit에서는 Annotation을 사용하면 제어가 쉬워진다. 다음 설명하는 애노테이션을 적으시오.
11-1.@BeforeClass
단위 테스트 안의 모든 메소드 실행 전에 단 한번만 수행
11-2. @AfterClass
단위 테스트 안의 모든 메소드 실행이 된 후 마지막에 단 한번만 수행
12-1. @Before
단위 테스트 안의 각 메소드가 실행될 때마다 실행 전에 수행
12-2. @After
단위 테스트 안의 각 메소드가 실행될 때마다 실행 후에 수행
[ 13~15 ] 다음은 JUnit을 이용한 테스트 코드이다. 물음에 답하시오.
public class CalculatorTest { 1) @Test public void testSum( ) { // fail("Not yet implemented"); Calculator cal = new Calculator(); 2) assertEquals(30, cal.sum(20,10)); System.out.println("test1"); } 1) @Test public void testSum1( ){ // fail("Not yet implemented"); Calculator cal = new Calculator(); 2) assertEquals(60, cal.sum(50,10)); System.out.println("test2"); } @BeforeClass public static void beforeTest( ) { System.out.println("BeforeClass"); } @AfterClass public static void afterTest( ) { System.out.println("AfterClass"); } @Before public static void setUp( ) { System.out.println("Before setUp"); } @After public static void tearDown( ) { System.out.println("after tearDown"); }
}
13. 위 코드는 jnuit을 이용한 테스트 수행 코드이다. 1번에 들어갈 애노테이션을 적으시오
@Test
14. 위 코드는 두 수의 합을 구하는 sum( ) 메소드를 테스트 하는 코드이다. 2에 들어갈 메소드를 적으시오. 이 메소드는 두 수의 합의 결과가 같은 지를 확인한다.
assertEquals
15. 위 코드를 실행했을 때 출력되는 출력문을 순서대로 적으시오.
BeforeClass Before setUp test1 after tearDown Before setUp test2 after tearDown AfterClass
외부 테스트 프로그램(케이스)을 작성하여 System.out으로 번거롭게 디버깅하지 않아도 됨 프로그램 테스트 시 걸릴 시간도 관리할 수 있게 해주며 오픈 소스이며, 플러그인 형태로 Eclipse에 포함되어 있음. 하나의 jar 파일로 구성 사용법 간단 JUnit은 보이지 않고 숨겨진 단위 테스트를 끌어내어 정형화시켜 단위 테스트를 쉽게 해주 는 테스트용 Framework JDK 1.4에서 추가된 assertXXX를 사용하여 Test를 진행 JUnit은 테스트 결과를 확인하는 것 이외 최적화된 코드를 유추해내는 기능도 제공 테스트 결과를 단순한 텍스트로 남기는 것이 아니라 Test클래스로 남김 개발자에게 테스트 방법 및 클래스의 History를 넘겨줄 수도 있음.
JUnit의 특징
1. 단위 테스트 Framework 중 하나 2. 문자 혹은 GUI 기반으로 실행됨 3. 단정문으로 테스트 케이스의 수행 결과를 판별함(assertEquals(예상 값, 실제 값)) 4. 어노테이션으로 간결하게 지원함 5. 결과는 성공(녹색), 실패(붉은색) 중 하나로 표시
Eclipse - JUnit 설정
1. Java Project를 생성 후 Project 이름에서 오른쪽 마우스를 클릭하고 Properties를 선택 2. Java BuildPath를 선택 3. Libraries 탭을 선택하고, Add Library를 선택 4. JUnit을 선택하고, Next 버튼 선택 5. 버전을 선택하고, Finish 버튼 선택 6. JUnit이 추가 된 사항을 확인
JUNIT 실행 방법
* 그림처럼 실행하거나 단위실행 가능하다.
com.calculator 패키지, Calculator 클래스 작성
Calculator.java
package com.calculator;
public class Calculator {
public int sum(int num1, int num2) {
return num1+num2;
}
public int mul(int num1, int num2) {
return num1*num2;
}
}
CalculatorTest.java
package com.calculator.test;
import static org.junit.Assert.*;
import org.junit.Test;
import com.calculator.Calculator;
public class CalculatorTest {
Calculator calculator = new Calculator();
@Test
public void testSum() {
assertEquals(30, calculator.sum(10,20));
}
public void testMul() {
assertEquals(100, calculator.mul(10,10));
}
}
대표적인 단정문
assertArrayEquals(a,b) : 배열 a와b가 일치함을 확인 assertEquals(a,b) : 객체 a와b의 값이 같은지 확인 assertSame(a,b) : 객체 a와b가 같은 객체임을 확인 assertTrue(a) : a가 참인지 확인 assertNotNull(a) : a객체가 null이 아님을 확인
2) 테스트 메소드 수행시간 제한하기
@Test(timeout=5000) //밀리초
public void testSum() {
}
3) 테스트 메소드 Exception 지정하기
@Test(expected=RuntimeException.class)
public void testSum() {
}
4) 초기화 및 해제
@BeforeClass, @AfterClass
- 메소드 위에 선언되면 해당 테스트 클래스는 한번만 수행
@BeforeClass
public static void setupBeforClass() throws Exception{
}
@AfterClass
public static void tearDownAfterClass() throws Exception{
}
@Before, @After가 메소드 위에 선언되면 해당 테스트 클래스 안에 메
소드들이 테스트 되기 전과 후에 각각 실행되게 지정하는 어노테이션
@Before
public void setUp() throws Exception{
}
@After
public void tearDown() throws Exception{
}
개발자가 지정한 SQL, 저장프로시저 그리고 몇가지 고급 매핑을 지원하는 퍼시스턴스 프레임워크 JDBC로 처리하는 상당부분의 코드와 파라미터 설정및 결과 매핑을 대신해 줌 데이터베이스 레코드에 원시타입과 Map 인터페이스 그리고 자바 POJO 를 설정해서 매핑하기 위해 XML과 애노테이션을 사 용할 수 있음
스프링 + MyBatis 연동 설정
1. 필수 라이브러리
• MyBatis 라이브러리 • mybatis-spring 라이브러리 • MySQL JDBC 드라이버
• 개발 전 테스트
• MySQL의 연결 테스트 • Spring 프로젝트의 SqlSessionFactory 연결 테스트
XML
(server) context.xml
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
--><!-- The contents of this file will be loaded for each web application --><Context>
<!-- Default set of monitored resources. If one of these changes, the -->
<!-- web application will be reloaded. -->
<WatchedResource>WEB-INF/web.xml</WatchedResource>
<WatchedResource>WEB-INF/tomcat-web.xml</WatchedResource>
<WatchedResource>${catalina.base}/conf/web.xml</WatchedResource>
<!-- driver, xe 수정 : 서버에 이부분을 뺀다 -->
<!-- <Resource name="jdbc/myoracleDB" auth="Container"
type="javax.sql.DataSource" driverClassName="oracle.jdbc.driver.OracleDriver"
url="jdbc:oracle:thin:@192.168.0.78:1521:xe"
username="mvc" password="1234" maxTotal="20" maxIdle="10"
maxWaitMillis="-1"/> -->
<!-- Uncomment this to disable session persistence across Tomcat restarts -->
<!--
<Manager pathname="" />
-->
</Context>
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
--><!-- The contents of this file will be loaded for each web application --><Context>
<!-- Default set of monitored resources. If one of these changes, the -->
<!-- web application will be reloaded. -->
<WatchedResource>WEB-INF/web.xml</WatchedResource>
<WatchedResource>WEB-INF/tomcat-web.xml</WatchedResource>
<WatchedResource>${catalina.base}/conf/web.xml</WatchedResource>
<!-- driver, xe 수정 -->
<!-- <Resource name="jdbc/myoracleDB" auth="Container"
type="javax.sql.DataSource" driverClassName="oracle.jdbc.driver.OracleDriver"
url="jdbc:oracle:thin:@192.168.0.78:1521:xe"
username="mvc" password="1234" maxTotal="20" maxIdle="10"
maxWaitMillis="-1"/> -->
<!-- Uncomment this to disable session persistence across Tomcat restarts -->
<!--
<Manager pathname="" />
-->
</Context>
이번에는 Spring MVC 패턴을 이용하여 게시판을 만들어보도록 하겠습니다. 우선 로직과 파일의 폴더 구성은 아래와 같습니다.
작업 순서도
1. DB작성 2. 프로젝트 생성 3. pom.xml, web.xml 수정
1. 테이블, 시퀀스 작성 후 테스트 데이터 입력
select * from tab;
create table mvc_board(
bno number primary key,
writer varchar2(20) not null,
title varchar2(100) not null,
content varchar2(1000) not null,
write_date DATE default SYSDATE,
hit int default 0);
create sequence mvc_board_seq;
insert into mvc_board(
bno, writer, title, content)
values (mvc_board_seq.nextval,
'kim', '제목1', '내용1입니다');
commit;
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
--><!-- Note: A "Server" is not itself a "Container", so you may not
define subcomponents such as "Valves" at this level.
Documentation at /docs/config/server.html
--><Server port="8006" shutdown="SHUTDOWN">
<Listener className="org.apache.catalina.startup.VersionLoggerListener"/>
<!-- Security listener. Documentation at /docs/config/listeners.html
<Listener className="org.apache.catalina.security.SecurityListener" />
-->
<!--APR library loader. Documentation at /docs/apr.html -->
<Listener SSLEngine="on" className="org.apache.catalina.core.AprLifecycleListener"/>
<!-- Prevent memory leaks due to use of particular java/javax APIs-->
<Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener"/>
<Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener"/>
<Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener"/>
<!-- Global JNDI resources
Documentation at /docs/jndi-resources-howto.html
-->
<GlobalNamingResources>
<!-- Editable user database that can also be used by
UserDatabaseRealm to authenticate users
-->
<Resource auth="Container" description="User database that can be updated and saved" factory="org.apache.catalina.users.MemoryUserDatabaseFactory" name="UserDatabase" pathname="conf/tomcat-users.xml" type="org.apache.catalina.UserDatabase"/>
</GlobalNamingResources>
<!-- A "Service" is a collection of one or more "Connectors" that share
a single "Container" Note: A "Service" is not itself a "Container",
so you may not define subcomponents such as "Valves" at this level.
Documentation at /docs/config/service.html
-->
<Service name="Catalina">
<!--The connectors can use a shared executor, you can define one or more named thread pools-->
<!--
<Executor name="tomcatThreadPool" namePrefix="catalina-exec-"
maxThreads="150" minSpareThreads="4"/>
-->
<!-- A "Connector" represents an endpoint by which requests are received
and responses are returned. Documentation at :
Java HTTP Connector: /docs/config/http.html
Java AJP Connector: /docs/config/ajp.html
APR (HTTP/AJP) Connector: /docs/apr.html
Define a non-SSL/TLS HTTP/1.1 Connector on port 8080
-->
<Connector connectionTimeout="20000" port="8081" protocol="HTTP/1.1" redirectPort="8443"/>
<!-- A "Connector" using the shared thread pool-->
<!--
<Connector executor="tomcatThreadPool"
port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
-->
<!-- Define a SSL/TLS HTTP/1.1 Connector on port 8443
This connector uses the NIO implementation. The default
SSLImplementation will depend on the presence of the APR/native
library and the useOpenSSL attribute of the
AprLifecycleListener.
Either JSSE or OpenSSL style configuration may be used regardless of
the SSLImplementation selected. JSSE style configuration is used below.
-->
<!--
<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
maxThreads="150" SSLEnabled="true">
<SSLHostConfig>
<Certificate certificateKeystoreFile="conf/localhost-rsa.jks"
type="RSA" />
</SSLHostConfig>
</Connector>
-->
<!-- Define a SSL/TLS HTTP/1.1 Connector on port 8443 with HTTP/2
This connector uses the APR/native implementation which always uses
OpenSSL for TLS.
Either JSSE or OpenSSL style configuration may be used. OpenSSL style
configuration is used below.
-->
<!--
<Connector port="8443" protocol="org.apache.coyote.http11.Http11AprProtocol"
maxThreads="150" SSLEnabled="true" >
<UpgradeProtocol className="org.apache.coyote.http2.Http2Protocol" />
<SSLHostConfig>
<Certificate certificateKeyFile="conf/localhost-rsa-key.pem"
certificateFile="conf/localhost-rsa-cert.pem"
certificateChainFile="conf/localhost-rsa-chain.pem"
type="RSA" />
</SSLHostConfig>
</Connector>
-->
<!-- Define an AJP 1.3 Connector on port 8009 -->
<Connector port="8010" protocol="AJP/1.3" redirectPort="8443"/>
<!-- An Engine represents the entry point (within Catalina) that processes
every request. The Engine implementation for Tomcat stand alone
analyzes the HTTP headers included with the request, and passes them
on to the appropriate Host (virtual host).
Documentation at /docs/config/engine.html -->
<!-- You should set jvmRoute to support load-balancing via AJP ie :
<Engine name="Catalina" defaultHost="localhost" jvmRoute="jvm1">
-->
<Engine defaultHost="localhost" name="Catalina">
<!--For clustering, please take a look at documentation at:
/docs/cluster-howto.html (simple how to)
/docs/config/cluster.html (reference documentation) -->
<!--
<Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/>
-->
<!-- Use the LockOutRealm to prevent attempts to guess user passwords
via a brute-force attack -->
<Realm className="org.apache.catalina.realm.LockOutRealm">
<!-- This Realm uses the UserDatabase configured in the global JNDI
resources under the key "UserDatabase". Any edits
that are performed against this UserDatabase are immediately
available for use by the Realm. -->
<Realm className="org.apache.catalina.realm.UserDatabaseRealm" resourceName="UserDatabase"/>
</Realm>
<Host appBase="webapps" autoDeploy="true" name="localhost" unpackWARs="true">
<!-- SingleSignOn valve, share authentication between web applications
Documentation at: /docs/config/valve.html -->
<!--
<Valve className="org.apache.catalina.authenticator.SingleSignOn" />
-->
<!-- Access log processes all example.
Documentation at: /docs/config/valve.html
Note: The pattern used is equivalent to using pattern="common" -->
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" pattern="%h %l %u %t "%r" %s %b" prefix="localhost_access_log" suffix=".txt"/>
<!-- <Context docBase="test1" path="/test1" reloadable="true" source="org.eclipse.jst.jee.server:test1"/>
<Context docBase="MVC_Board" path="/MVC_Board" reloadable="true" source="org.eclipse.jst.jee.server:MVC_Board"/>
<Context docBase="exam01" path="/exam01" reloadable="true" source="org.eclipse.jst.jee.server:exam01"/> -->
<Context docBase="SpringMVCBoard01" path="/springboard" reloadable="true" source="org.eclipse.jst.jee.server:SpringMVCBoard01">
<!-- driver, xe 수정
<Resource name="jdbc/myoracle" auth="Container"
type="javax.sql.DataSource" driverClassName="oracle.jdbc.driver.OracleDriver"
url="jdbc:oracle:thin:@192.168.0.78:1521:xe"
username="mvc" password="1234" maxTotal="20" maxIdle="10"
maxWaitMillis="-1"/> -->
</Context></Host>
</Engine>
</Service>
</Server>
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
--><!-- The contents of this file will be loaded for each web application --><Context>
<!-- Default set of monitored resources. If one of these changes, the -->
<!-- web application will be reloaded. -->
<WatchedResource>WEB-INF/web.xml</WatchedResource>
<WatchedResource>WEB-INF/tomcat-web.xml</WatchedResource>
<WatchedResource>${catalina.base}/conf/web.xml</WatchedResource>
<!-- driver, xe 수정 -->
<Resource name="jdbc/myoracleDB" auth="Container"
type="javax.sql.DataSource" driverClassName="oracle.jdbc.driver.OracleDriver"
url="jdbc:oracle:thin:@192.168.0.78:1521:xe"
username="mvc" password="1234" maxTotal="20" maxIdle="10"
maxWaitMillis="-1"/>
<!-- Uncomment this to disable session persistence across Tomcat restarts -->
<!--
<Manager pathname="" />
-->
</Context>
자동으로 Maven Repository로 연결이 되는 mysql과 달리 오라클은 유료 프로그램이기 때문에 직접 연결을 해 주어야 한다. Build Path를 눌러 Java Build Path > Add External JARs 그리고 Deployment Assembly > Java Build Path Entiries 를 눌러 두 가지를 추가해준다.
web.xml 수정 : <webapp></webapp>에 Character Encoding Filter 삽입
애플리케이션의 역할을 모델(Model), 뷰(View), 컨트롤러(controller)로 나누어 작업 Smalltalk-80 처음 소개 업무 서비스와 도메인 객체를 사용자 인터페이스로부터 분리, 하나 이상의 컨트롤러를 통해서 이들 사이 상호작용을 통제하는 아키텍처 패턴
MVC 모델 구성 요소
모델 : 데이터를 실어서 보내준다.
애플리케이션의 핵심적인 기능 제공 뷰와 컨트롤러 등록 데이터 변경 시 뷰와 컨트롤러에 통지
뷰
관련된 컨트롤러 생성, 초기화, 사용자에게 정보 표시 데이터 변경이 통지될 때 모델로부터 데이터를 읽어 처리
컨트롤러
사용자 입력을 이벤트로 받아들여 해석하여 모델에 대한 요청을 서비스하거나 뷰에 대한 요청을 표시 데이터 변경이 통지될 때 모델로부터 데이터 읽어와 처리 Front Controller 패턴 적용 – 컨트롤러가 중심이 되는 변형된 구조를 가짐 (이전 글의 BoardServlet 같은 전단서블릿)
클라이언트가 컨트롤러에게 데이터 조회, 저장 등의 작업 요청 컨트롤러 : 서블릿으로 구현, 업무 로직 처리, 모델생성, 모델의 데이터 갱신, 뷰에 모델 전송, 뷰가 변경된 데이터 사용 가능하게 함 모델 : POJO Java 클래스로 구현, 데이터와 데이터처리에 필요한 메서드 포함, 자신이 관리하는 데이터에 집중 뷰 : JSP로 구현, 컨트롤러가 제공한 모델을 사용하여 데이터에 액세스하여 웹페이지(뷰)를 렌더링하여 응답을 생성하고 컨트롤러에 전달 컨트롤러는 클라이언트에 응답을 전송하고 서비스 종료
Spring MVC 매커니즘
BoardServlet 만들 필요 없이 기본으로 Servlet MVC 패턴은 Dispatcher Servlet을 제공한다. 또한 annotation도 제공한다.
1. 핸들러 맵핑 : 어떤 요청이 들어왔는지 확인한다. 2. 실질적으로 일을 처리할 컨트롤러를 선택한다. 3. 처리 결과를 Model(데이터를 실어준다)과 논리View(데이터를 표시)로 다시 Dispatcher Servlet으로 돌려준다. 4. ViewResolver, 진짜 물리적인 뷰를 찾아서 내용을 보여준다.
* 논리뷰와 물리적인 뷰의 차이는>
스프링 프로젝트 작성 두 가지 방법
Spring Boot를 이용하는 방법
File -> new -> Spring Start Project
Spring 템플릿 프로젝트를 이용하는 방법 (이 글에서 사용할 전통적인 방법) File>New>Spring Legacy Project New Spring Project 위저드의 Spring Project 화면에서 Spring MVC Project 항목을 선택, 프로젝트 이름: SpringProject01로 지정하고 next 선택 Project Setting>Spring MVC Project화면에서 패키지명을 com.pgm.project01로 지정, finish 선택
<filter>
<filter-name>characterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping> //필터 지정 위치
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
root 웹 애플리케이션 컨텍스트
IoC 컨테인 애플리케이션 컨텍스트는 트리 구조를 가짐 모든 애플리케이션 컨텍스트는 부모 애플리케이션 컨텍스트를 가질 수 있으며, 계층구조 안에 모든 애플리케이션 컨텍스트는 각각 독립적인 설정 정보를 사용하여 Spring 빈 객체를 생성하고 관리 의존성 주입을 위해 Spring 빈을 찾을 때 먼저 자신의 애플리케이션컨텍스트를 관리하는 Spring 빈 중에서 찾는다 자신을 관리하는 Spring 빈 중에 없는 경우 부모 애플리케이션 컨텍스에게 Spring 빈을 찾아 줄 것을 요청 계층구조를 따라 최상위 root 컨텍스트까지 요청 가능
컨트롤러 구현
데이터를 받는 두 가지 방법
데이터(커맨드) 객체 이용
Get /Post 방식 처리
실습하기
1. Spring Legacy Project프로젝트를 생성한다.
스프링은 항상 디폴트 패키지를 적어야한다. 사용하지 않는 프로젝트는 클로즈 시켜서 닫아두어야 엉키는 등의 에러가 없다.
처음 플젝 만들 때마다 시작 전 구축이 빨라진 이유는 아래 사진처럼 디폴트로 받아야하는 라이브러리가 이미 생성되어있기 때문이다.
2. Maven Repository 바로가기
스프링의 장점! 직접 찾아 라이브러리를 넣어줄 필요없이 pom.xml에 라이브러리를 등록해놓으면 알아서 프로그램이 찾아간다.
package controller;
import controller.service.BoardDeleteService;
import controller.service.BoardListService;
import controller.service.BoardService;
import controller.service.BoardUpdateService;
import controller.service.BoardViewService;
import controller.service.BoardWriteFormService;
import controller.service.BoardWriteService;
public class ActionFactory {
//싱글톤
private ActionFactory () {}
private static ActionFactory af = new ActionFactory();
public static ActionFactory getInstance() {
return af;
}
public BoardService getService(String command) {
BoardService service = null;
if(command.equals("/list.do"))
service = new BoardListService();
else if(command.equals("/writeForm.do")) {
service = new BoardWriteFormService();
}else if(command.equals("/write.do")) {
service = new BoardWriteService();
}else if(command.equals("/view.do")) {
service = new BoardViewService();
}else if(command.equals("/update.do")) {
service = new BoardUpdateService();
}else if(command.equals("/delete.do")) {
service = new BoardDeleteService();
}
return service;
}
}
index(뷰)에서 요청 -> boardservlet 에서 do/post 중 하나 -> process에서 request정보, 전체 uri 중 contextpath(프로젝트 우측 버튼, 프로퍼티에 가면 web project setting의 context root)를 가져온다. (index 앞의 response.sendRedirect("list.do"); list.do 앞에 이것저것 붙는다. ) uri는 실제 리소스 주소 (MVC_Board/list.do)다. url은 http부터.
contextpath.length() 는 길이. 전체 주소에서 path의 길이 (/ 포함) 어떤 값이 나오는 게 궁금하면 System.out.println(requestURI....contextpath...command)등으로 출력해본다.
BoardServlet의 BoardService에서 서비스를 얻기위해
ActionFactory 서비스 생성 후 레퍼런스 리턴
다시 BoardServlet 와서 request, response 참조값을 가지고 함수 호출..
1. 이클립스 + 스프링 플러그인 Help -> Eclipse Marketplace에서 Spring Tools Add-On 3.9.7.Release 확장 프로그램 설치
2. STS(Spring Tool Suite) 이클립스에 스프링 플러그인이 포함된 버전 https://spring.io/tools 에서 STS4 다운로드(윈도우 64bit용) 압축을 해제한 후 ecplipsec.exe 또는 SpringToolSuite4.exe 실행 에러가 발생할 경우 – 한경변수에 JAVA_HOME, path에 JAVA_HOME/bin 추가 주의 : sts 설치디렉토리 및 workspace는 한글 이름이 들어간 디 렉토리를 사용하지 말 것
3. InteliJ
아래 core 에서 64bit 버전을 받아 (본인의 컴퓨터는 64bit므로) 압축파일을 풀어 C드라이브에 위치한다.
파일의 경로나 이름이 길면 에러가 발생할 수 있으니 C드라이버에 sts3.zip으로 이름을 변경해서 압축 해제한다. 지금받는 파일은 일종의 이클립스라고 보면 된다. 만일 이클립스가 열려있으면 닫은 뒤 sts프로그램을 실행해준다. exe파일은 아래 경로에 있다.
실행시키면 이클립스처럼 뜬다. 아까 서버를 연결해두었던 프로젝트라 연결되어있는 것을 확인할 수 있다.
스프링 뿐만 아니라 거의 모든 프로젝트를 만들어 작업할 수 있다.
다음으로는 테스트 프로젝트를 생성한다.
그 이전의 팝업은 OK하고 패키지 경로는 3단계로 자유로이 적어준다. url 거꾸로 적듯 하는건데 com.lje.test1으로 했다. 보통 두번째는 회사명 세번째는 프로젝트명으로 많이 만든다. 생성 후 플젝에 에러뜨는 것은 라이브러리를 아직 받는 중이어서 그렇다. 그래도 이전처럼 직접 라이브러리를 받을 필요가 없어져서 좋아진거라고 한다.
서버를 돌려본다.
언어설정
Web
4버전으로 새로운 경로폴더를 만들었는데 이 버전은 기본 스프링 > 레거시프로젝트가 없다.
서버 연결 후 윈도우 > 이클립스 마켓플레이스 > 스프링 검색 후 3 Add on 설치하면 레거시프로젝트 사용 가능
* 사전적 의미 : ‘어떤 것을 구성하는 구조 또는 뼈대’ 소프트웨어적 의미로는 ’기능을 미리 클래스나 인터페이스 등으로 만들어 제공하는 반제품’을 뜻한다.
프레임워크(Framework) 장점
1. 일정한 기준에 따라 개발이 이루어지므로 개발 생산성과 품질이 보장된 애플리케이션을 개발할 수 있음 2. 개발 후 유지보수 및 기능의 확장성에서도 고품질 보장 * 소형 프로젝트는 jsp모델1을 쓰나 형태가 커지면 모델 뷰 컨트롤러를 분리하는 게 맞다.
스프링 프레임워크 정의
1. 스프링 프레임워크(이하 스프링)는 자바 웹 애플리케이션 개발을 위한 오픈소스 프레임워크 2. EJB(Enterprise Java Bean, 엔터프라이즈 자바 빈즈)보다 경량 프레임워크(lightWeight Framework) EJB는 서버클라이언트를 조절하기에 기능이 많아 편리하다. 그러나 고성능 서버를 요구한다. * 환경설정 이해가 중요하다. jsp로 구축한 이전 과정에 비해 상대적으로 쉬운 편.
스프링 프레임워크 특징
1. 의존성 주입(DI: Dependency Injection) 클래스 객체를 개발자가 코드에서 생성하지 않고 프레임워크가 생성하여 사용하는 방법
2. 제어 역행(IoC: Inversion of Control) 개발자가 필요한 코드를 작성, 특정 구조에 포함 서블릿이나 빈 등을 개발자가 코드에서 생성하지 않고 프레임워크가 직접 수행하는 방법
3. 관점지향(AOP : Aspect Oriented Programming) 관심사의 분리 (Seperation of Concerns) 핵심 기능 외 부수 기능들을 분리 구현함으로써 모듈성을 증가시키는 방법 보안, 트랜잭션, 로깅 처리 등이 대표적
4. POJO(plain old java object) 방식 프레임워크 특정 규약과 환경에 종속되지 않는다. 단일 책임 원칙을 지키는 클래스
컨테이너(Container) 정의
1. 톰캣은 서블릿 컨테이너라고 부르는데, 그 이유는 톰캣을 실행하면 톰캣은 서블릿의 생성, 초기화, 서비스 실행, 소멸에 관한 모든 권한을 가지고 서블릿을 관리
2. 스프링은 애플리케이션에서 사용되는 여러 가지 빈(클래스 객체)을 개발자가 아닌스프링이 권한을 가지고 직접 관리
스프링의 특징
1. EJB보다 가볍고 배우기도 쉬우며 경량 컨테이너의 기능을 수행 2. 제어 역행(IoC, Inversion of Control) 기술을 이용해 애플리케이션 간의 느슨한 결합을 제어함. 3. 의존성주입(DI, Dependency Injection) 기능을 지원함 : 클래스 내에서 다른 객체를 사용하는 것 4. 관점 지향(AOP, Aspect-Oriented Programming) 기능을 이용해 자원 관리 : 핵심 비핵심 기능을 분리해 처리 5. 영속성과 관련된 다양한 서비스를 지원함 6. 수많은 라이브러리와의 연동 기능을 지원
<resources>
<!--
TODO: Before you run your application, you need a Google Maps API key.
To get one, follow this link, follow the directions and press "Create" at the end:
https://console.developers.google.com/flows/enableapi?apiid=maps_android_backend&keyType=CLIENT_SIDE_ANDROID&r=C2:A9:31:6B:97:C3:EF:81:A9:A6:23:C1:A7:62:C9:45:D0:AF:13:DB%3Bcom.example.googlemaptest
You can also add your credentials to an existing key, using these values:
Package name:
C2:A9:31:6B:97:C3:EF:81:A9:A6:23:C1:A7:62:C9:45:D0:AF:13:DB
SHA-1 certificate fingerprint:
C2:A9:31:6B:97:C3:EF:81:A9:A6:23:C1:A7:62:C9:45:D0:AF:13:DB
Alternatively, follow the directions here:
https://developers.google.com/maps/documentation/android/start#get-key
Once you have your key (it starts with "AIza"), replace the "google_maps_key"
string in this file.
-->
<string name="google_maps_key" templateMergeStrategy="preserve" translatable="false">
여기에 키를 입력
</string>
</resources>
MainActivity.java
package com.example.googlemaptest;
import androidx.fragment.app.FragmentActivity;
import android.os.Bundle;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.MarkerOptions;
public class MapsActivity extends FragmentActivity implements OnMapReadyCallback {
private GoogleMap mMap;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_maps);
// Obtain the SupportMapFragment and get notified when the map is ready to be used.
SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
.findFragmentById(R.id.map);
mapFragment.getMapAsync(this);
}
/**
* Manipulates the map once available.
* This callback is triggered when the map is ready to be used.
* This is where we can add markers or lines, add listeners or move the camera. In this case,
* we just add a marker near Sydney, Australia.
* If Google Play services is not installed on the device, the user will be prompted to install
* it inside the SupportMapFragment. This method will only be triggered once the user has
* installed Google Play services and returned to the app.
*/
@Override
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
// Add a marker in Sydney and move the camera
LatLng sydney = new LatLng(-34, 151);
mMap.addMarker(new MarkerOptions().position(sydney).title("Marker in Sydney"));
mMap.moveCamera(CameraUpdateFactory.newLatLng(sydney));
}
}
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.googlemaptest">
<!--
The ACCESS_COARSE/FINE_LOCATION permissions are not required to use
Google Maps Android API v2, but you must specify either coarse or fine
location permissions for the 'MyLocation' functionality.
-->
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<!--
The API key for Google Maps-based APIs is defined as a string resource.
(See the file "res/values/google_maps_api.xml").
Note that the API key is linked to the encryption key used to sign the APK.
You need a different API key for each encryption key, including the release key that is used to
sign the APK for publishing.
You can define the keys for the debug and release targets in src/debug/ and src/release/.
-->
<meta-data
android:name="com.google.android.geo.API_KEY"
android:value="@string/google_maps_key" />
<activity
android:name=".MapsActivity"
android:label="@string/title_activity_maps">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>