VirtualBox 해상도 조절


1. 설치할 패키지의 최신 버전 정보를 갱신한다.
1
$ sudo apt-get update
cs

2. VirtualBox 게스트 확장 패키지를 설치한다.
1
$ sudo apt-get install virtualbox-guest-dkms virtualbox-guest-utils virtualbox-guest-x11
cs

* virtualbox-guest-x11 설치시 의존성 에러가 발생한다면 아래 명령을 수행한다.
1
2
3
$ sudo apt-get remove libcheese-gtk23
$ sudo apt-get install xserver-xorg-core
$ sudo apt-get install -f virtualbox-guest-x11
cs
3. 종료 후 재시작 시킨다.
1
$ sudo shutdown -r now
cs

해상도가 정상적으로 나타난다.


'Development > Tool' 카테고리의 다른 글

IntelliJ PMD Plugin  (0) 2018.08.04
IntelliJ 단축키 정리  (0) 2017.03.21
반복문 성능 비교

반복문에는 크게 for, while 문이 있다. while 문은 잘못하면 무한 루프에 빠지기 쉬우므로 for문을 권장한다.
또한  반복문 안에서 꼭 필요하지 않은 소스는 반복문 밖으로 추출시키도록 한다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class Sample {
 
  public static void main(String args[]) {
 
    List<Integer> list = new ArrayList<>();
    for (int i = 0; i < 10000; i++) {
      list.add(i);
    }
 
 
    for (int i = 0; i < list.size(); i++) { // #1
      System.out.println(list.get(i).toString());
    }
 
    int size = list.size();
    for (int i = 0; i < size; i++) { // #2
      System.out.println(list.get(i).toString());
    }
 
    for (Integer integer : list) { // #3
      System.out.println(integer.toString());
    }
 
  }
}
cs

위와 같은 반복문의 경우, 어떤 것이 가장 빠를까?
빠른 순서로 나열하면 다음과 같다. #2 > #1 > #3 

#1처럼 조건식에 list.size()를 사용하면 size() 메소드가 반복 호출된다. #2처럼 변수로 선언하여 사용하는 것이 좋다.
#3은 JDK 1.5부터 지원하는 향상된 for문이다. 배열이나 컬렉션에 저장된 요소들을 별도의 형변환이나 get 메소드가 필요없어 편리하게 처리할 수 있다.
단, 처음부터 끝까지 모든 요소를 반복할 때에 권장한다. 순서를 반대로하거나 특정 요소부터 탐색할 때에 부적절하다. 

물론 성능 차이가 얼마나지 않는다. 하지만 규모가 크거나 반복 횟수가 큰 경우 성능에 지장을 줄 수 있다.

'Development > Java' 카테고리의 다른 글

Garbage Collection 과정  (0) 2018.04.28
Garbage Collection 용어 정리  (0) 2018.04.26
AES256 암호화 오류 해결  (4) 2017.10.06
List 중복 제거  (0) 2017.07.13
Reflection 클래스 정보  (0) 2017.07.12
CORS(Cross-Origin Resource Sharing)


웹 개발시 JavaScript로 외부 서버에 ajax요청을 날리면 웹 브라우저의 콘솔창에 에러 메시지가 출력되면서 요청이 실패한다.
외부로 요청이 안되는 것은 JavaScript 엔진 표준 스팩에 동일 출처 정책이라는 보안 규칙이 있기 때문이다.

동일 출처 정책(Same-Origin Policy)
JavaScript(XMLHttpRequest)로 다른 웹 페이지에 접근할 때에 동일 출처의 페이지로만 접근이 가능하다. 
동일 출처라는 것은 프로토콜, 호스트명, 포트가 같은 것을 의미한다. 
즉 웹 페이지의 스크립트는 그 페이지와 같은 서버에 있는 주소로만 ajax 요청할 수 있다는 것이다.

이 정책이 초기에는 웹 사이트의 보안을 위한 좋은 방법으로 생각되었으나 최근들어 여러 도메인에 걸처서 구성되는 대규모 웹 프로젝트가 늘어나고, REST API 등을 이용한 외부 호출이 많은 상황에서는 까다로운 기술이기도 하다. 
그래서 CORS라는 정책이 만들어졌다. 특징으로는 서버에서 외부 요청을 허용할 경우 ajax요청이 가능해지는 방식이다.

CORS(Cross-Origin Resource Sharing)
CORS는 웹 페이지의 제한된 자원을 외부 도메인에서의 접근을 허용해주는 매커니즘이다.
브라우저와 서버간의 Cross-Origin 요청 허용여부를 안전하게 결정하도록 상호작용할 수 있는 방법을 정의한다.

요청 URL이 외부 도메인일 경우 웹 브라우저는 preflight 요청을 먼저 날린다. preflight 요청은 실제로 요청하려는 경로와 같은 URL에 대해 OPTIONS 메소드를 미리 날려 요청할 수 있는 권한이 있는지 확인한다. 서버로 넘어온 preflight  요청을 처리하여 웹 브라우저에서 실제 요청을 날릴 수 있도록 접근 허용 설정을 해줘야 한다. 권한이 없으면 에러를 발생시키고 권한이 있으면 실제 요청을 처리 해준다.

* Request headers (클라이언트의 요청 헤더)
Origin: 요청을 보내는 페이지의 도메인
Access-Control-Request-Method: 실제 요청하려는 메소드 종류
Access-Control-Request-Headers: 실제 요청에 포함되어 있는 헤더 이름

* Response headers (서버에서의 응답 헤더)
Access-Control-Allow-Origin: 요청을 허용하는 출처. * 인 경우, 모든 도메인의 요청을 허용한다.
Access-Control-Allow-Methods: 요청을 허용하는 메소드 종류. 헤더 값에 해당하는 메소드만 접근 허용한다. (default : GET, POST)
Access-Control-Allow-Headers: 요청을 허용하는 헤더 이름
Access-Control-Max-Age: 클라이언트에서 preflight 의 요청 결과를 저장할 시간(sec). 해당 시간동안은 preflight요청을 다시 하지 않게 된다.

위의 request header 값을 보고 response header에 해당 출처(origin)에 허용하는 요청 스펙을 허용해주도록 Filter나 Interceptor 등으로 구현해야 한다. 
아래와 같이 Spring Framework에서 제공하는 방법으로 구현할 수도 있다.

Controller method CORS configuration
@CrossOrigin 어노테이션을 사용하여 클래스/메소드 레벨로 정의하여 사용할 수 있다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@CrossOrigin(maxAge = 3600)
@RestController
@RequestMapping("/account")
public class AccountController {
 
    @CrossOrigin("http://domain.com")
    @RequestMapping("/{id}")
    public Account retrieve(@PathVariable Long id) {
        // ...
    }
 
    @RequestMapping(method = RequestMethod.DELETE, path = "/{id}")
    public void remove(@PathVariable Long id) {
        // ...
    }
}
cs

Global CORS configuration - Java Config
Spirng MVC 기반의 전역 설정으로 Filter와 흡사하고 @CrossOrigin과 함께 사용할 수 있다.
1
2
3
4
5
6
7
8
9
10
11
12
@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/api/**")
             .allowedOrigins("http://domain.com")
             .allowedMethods("PUT""DELETE")
             .allowedHeaders("header1""header2""header3")
             .allowCredentials(false).maxAge(3600);
    }
}
cs

Filter based CORS support
Spring Framework 에서 지원하는 CorsFilter를 사용하거나 Custom하여 사용할 수 있다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
 
public class MyCorsFilter extends CorsFilter {
 
    public MyCorsFilter() {
        super(configurationSource());
    }
 
    private static UrlBasedCorsConfigurationSource configurationSource() {
        CorsConfiguration config = new CorsConfiguration();
        config.setAllowCredentials(true);
        config.addAllowedOrigin("http://domain.com");
        config.addAllowedHeader("*");
        config.addAllowedMethod("*");
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", config);
        return source;
    }
}
cs

출처 - http://adrenal.tistory.com/16

List 중복 제거

자바에서 List에 있는 값들 중에 중복된 값만 제외시키고 싶은 경우가 있다.
루프를 돌면서 유니크한 값인지 비교하는 로직을 사용하고 싶지 않았다.
중복을 허용하지 않는 HashSet으로 변환시키고 다시 List로 변환시키면 유니크한 값으로 이루어진 List를 만들 수 있다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class Sample {
 
    public static void main(String args[]) {
 
        List<String> items = new ArrayList<>();
        items.add("a");
        items.add("b");
        items.add("c");
        items.add("b");
        items.add("c");
        System.out.println(items); // ["a", "b", "c", "b", "c"]
 
  items = new ArrayList<>(new HashSet<>(items)); 
        System.out.println(items); // ["a", "b", "c"]
    }
}

cs

대소문자까지 중복된 값을 제외시킬 수 있는 좋은 방법 있으시면 피드백 부탁드립니다~

'Development > Java' 카테고리의 다른 글

Garbage Collection 과정  (0) 2018.04.28
Garbage Collection 용어 정리  (0) 2018.04.26
AES256 암호화 오류 해결  (4) 2017.10.06
반복문 성능 비교  (0) 2017.07.27
Reflection 클래스 정보  (0) 2017.07.12
Reflection 클래스 정보


Java에서 제공하는 Relfection API를 통해 동적으로 클래스에 관련된 정보를 가져올 수 있다.

* Class 클래스 주요 메소드
String getName() : 패키지 포함 해당 클래스명 리턴
String getSimpleName() : 해당 클래스명 리턴
Field[] getFields() : public으로 선언된 변수 목록 리턴
Field[] getDeclaredFields() : 해당 클래스에 선언된 모든 변수 리턴
Method[] getMethods() : public으로 선언된 메소드 목록 리턴(해당 클래스에서 사용 가능한 상속 받은 메소드 포함)
Method[] getDeclaredMethods() : 해당 클래스에 선언된 모든 메소드 리턴
Constructor[] getDeclaredConstructors() : 해당 클래스에 선언된 모든 생성자 리턴
int getModifiers() : 해당 클래스의 접근자 정보 리턴
String toString() : 해당 클래스 객체를 문자열로 리턴

* Method 클래스 주요 메소드
String getName() : 해당 메소드명 리턴
int getModifiers() : 해당 메소드의 접근자 정보 리턴
String toString() : 해당 메소드 정보 리턴
Object invoke(Object obj, Object... args) : 해당 메소드 수행
Class<?> getDeclaringClass() : 해당 메소드가 선언된 클래스 정보 리턴
Class<?> getReturnType() : 해당 메소드 리턴 타입 리턴
Class<?>[] getExceptionTypes() : 해당 메소드 예외 타입들 리턴
Class<?>[] getParameterTypes() : 해당 메소드 매개변수 타입들 리턴

* Field 클래스 주요 메소드
String getName() : 해당 변수명 리턴
int getModifiers() : 해당 변수의 접근자 정보 리턴
String toString() : 해당 변수 정보 리턴

Modifier.toString(int modifier) : int 타입으로 리턴받은 modifier 값을 문자열로 리턴

* 참고사항
- 로그 선언시 클래스 이름을 알아내기 위해 this.getClass().getName() 사용한다고 성능이 크게 저하되지는 않는다. 
  하지만 클래스 객체를 얻는 방법 보다는 클래스명을 직접 명시하는 것을 권장한다.
- 클래스의 이름으로 해당 객체의 타입인지 비교하는 방법 보다 instanceof 키워드를 사용하는 것이 성능이 우수하다.
클래스의 메타 데이터 정보는 JVM의 Perm 영역에 저장된다. 
   Class 클래스를 사용하여 많은 양의 클래스를 동적으로 생성하면 Perm 영역을 더 이상 사용할 수 없게 되어 OutOfMemoryError가 발생한다.

참고서적 - 자바 성능 튜닝 이야기


'Development > Java' 카테고리의 다른 글

Garbage Collection 과정  (0) 2018.04.28
Garbage Collection 용어 정리  (0) 2018.04.26
AES256 암호화 오류 해결  (4) 2017.10.06
반복문 성능 비교  (0) 2017.07.27
List 중복 제거  (0) 2017.07.13

요청 포워딩 처리

요청에 대한 응답을 누가할지 선택할 수 있다.
웹 애플리케이션에 있는 다른 컴포넌트에게 처리를 위임하거나 요청을 완전히 다른 URL로 방향을 바꿀 수 있다.

1. RequestDispatcher 클래스를 이용한 forward 방법

웹 브라우저를 통해 사용자가 서블릿에 최초 요청하면 HttpServletRequest 객체가 자동으로 생성된다.
이 request 객체를 사용해 응답을 처리하는 웹 컴포넌트(서블릿, JSP, HTML)로 재요청하는 방식이다.
최초/재요청 동일한 HttpServletRequest 객체를 사용하기 때문에 URL 변동이 없다.
따라서 웹 브라우저 입장에서는 누가 처리한 것인지 알 수 없다.
또한, 동일한 객체를 사용하기 때문에 최초 요청시 request scope에 attribute를 설정하면 재요청시 설정된 attribute 값을 가져올 수 있다.

1
2
RequestDispatcher dispatcher = request.getRequestDispatcher(target);
dispatcher.forward(request, response);
cs

2. HttpServletResponse 클래스를 이용한 redirect 방법

forward 방식과 동일하게 다른 웹 컴포넌트에게 재요청하는 방식이다.
차이점은 최초 요청에 대한 응답시 HttpServletResponse 객체의 상태코드 헤더에 301 값과 Location 헤더에 새로운 URL 값을 포함시킨다.
웹 브라우저는 응답받은 URL로 재요청하기 때문에 동일한 HttpServletRequest가 아닌 새로운 request 객체가 생성된다.
따라서 URL이 변경되고 attribute에 설정된 값을 가져올 수 없다.

1
response.sendRedirect(target);
cs


JDBC 오라클 데이터베이스 연동하기


먼저 오라클 데이터베이스 설치하여 emp 테이블을 생성한 전제로 진행한다. (다운로드 - www.oracle.com)
오라클 드라이버를 클래스 패스에 설정해야 자바 애플리케이션과 오라클 데이터베이스를 연동할 수 있다.
[Windows]-[Preferences]-[Java]-[Build Path]-[ClassPath Variables]에 있는 JRE_LIB 경로를 파악하여
lib\ext 디렉토리에 오라클 설치경로(C:\oraclexe\app\oracle\product\11.2.0\server\jdbc\lib)에 있는'ojdbc6_g.jar'
파일을 복사하면 자동으로 드라이버가 클래스 패스에 추가된다.

* Select 쿼리 예제

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
@WebServlet("/select")
public class SelectServlet extends HttpServlet {
 
    private static final long serialVersionUID = -2214077158028938610L;
 
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
 
        String driver = "oracle.jdbc.OracleDriver"// 오라클 드라이버 클래스 파일명
        String url = "jdbc:oracle:thin:@localhost:1521:XE"// 오라클 위치,포트번호,DB정보
        String id = "root"// 오라클 접속 계정
        String password = "1234"// 오라클 접속 비밀번호
 
        Connection con = null;
        Statement stmt = null;
        ResultSet rs = null;
        String result = null;
        
        try {
            Class.forName(driver); // 드라이버 로딩
            con = DriverManager.getConnection(url, id, password); // DB 커넥션 맺기
 
            String sql = "select eid, ename, salary from emp";
            stmt = con.createStatement();
            rs = stmt.executeQuery(sql);
 
            while (rs.next()) {
                String eid = rs.getString("eid");
                String ename = rs.getString("ename");
                int salary = rs.getInt("salary");
                result  = eid + " " + ename + " " + salary;
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try { // 자원 반납
                if (rs != null)
                    rs.close();
                if (stmt != null)
                    stmt.close();
                if (con != null)
                    con.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
 
        request.setAttribute(result, result);
        response.setCharacterEncoding("UTF-8");
        request.getRequestDispatcher("/select.jsp").forward(request, response);
    }
 
}
cs
Select 쿼리 요청에는 executeQuery 메소드를 사용하여 테이블 형태인 ResultSet 객체를 얻는다.
ResultSet 객체는 포인터를 이용해서 원하는 데이터를 얻을 수 있기 때문에 먼저 포인터를 이용해서 레코드를 선택하고 포인터가 가리키는 레코드의 컬럼을 지정해서 데이터를 얻는다. 레코드를 선택하는 메소드는 next()를 사용하고 컬럼은 데이터형에 맞는 get*(컬럼명)메소드를 사용한다.

파일 및 데이터베이스는 외부 자원이기 때문에 사용한 후에는 반드시 자원을 해제시켜야 된다. 해제시킬 때에는 사용한 역순으로 해제시킨다.
예외 발생 여부에 관계없이 항상 자원을 반납해야하므로 finally 문에 코드를 구현하도록 한다.

* Update 쿼리 예제

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
@WebServlet("/update")
public class UpdateServlet extends HttpServlet {
 
    private static final long serialVersionUID = -2214077158028938610L;
 
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
 
        request.setCharacterEncoding("UTF-8");
        String eid = request.getParameter("eid");
        String ename = request.getParameter("ename");
        int salary = Integer.parseInt(request.getParameter("salary"));
        
        String driver = "oracle.jdbc.OracleDriver";
        String url = "jdbc:oracle:thin:@localhost:1521:XE";
        String id = "root";
        String password = "1234";
        
        Connection con = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        
        try {
            Class.forName(driver);
            con = DriverManager.getConnection(url, id, password);
        
            String sql = "update emp set ename = ?, salary = ? where eid = ?";
            pstmt = con.prepareStatement(sql);
            pstmt.setString(1, ename);
            pstmt.setInt(2, salary);
            pstmt.setString(3, eid);
            
            int count = pstmt.executeUpdate();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (rs != null)
                    rs.close();
                if (pstmt != null)
                    pstmt.close();
                if (con != null)
                    con.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        
        response.setCharacterEncoding("UTF-8");
        response.sendRedirect("/select?eid=" + eid);
    }
    
}
cs
PrepareStatement 객체를 이용하면 SQL 문을 먼저 작성하고 나중에 필요한 데이터를 설정할 수 있다.
set 메소드를 이용해 인덱스에 값을 지정한다. 인덱스는 작성한 SQL 문에 있는 '?' 심벌의 순서를 의미한다. 
'?' 심벌 수와 set 메소드 수는 같아야 한다.

DML(Insert, Update, Delete) 쿼리 요청에는 executeUpdate 메소드를 사용하여 데이터를 처리하고 변경된 레코드의 개수를 얻는다.


어노테이션을 이용한 초기화파라미터/리스너/필터 등록하기


어노테이션을 사용하기 위해 프로젝트의 웹 모듈 버전은 3.0 이상으로 설정해야 한다.

ServletConfig API를 활용한 초기화 파라미터 사용
초기화 파라미터는 여러 서블릿에서 공유해서 사용하지 못하고 등록된 서블릿에서만 사용할 수 있다.
(웹 애플리케이션 범위의 초기화 파라미터를 사용하려면 ServletContext API를 사용해야 한다.)

1
2
3
4
5
6
7
8
9
10
11
@WebServlet(name = "init", urlPatterns = { "/init" }, initParams = {
@WebInitParam(name = "dirPath", value = "D:\\test"), @WebInitParam(name = "id", value = "root") })
public class AnnoInitParam extends HttpServlet {
 
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) 
throws ServletException, IOException {
        System.out.println(getInitParameter("dirPath")); // d:\\test
        System.out.println(getInitParameter("id"));      // root
    }
 
}
cs

ServletContextListener API
웹 애플리케이션도 서블릿처럼 라이프사이클을 가진다. 톰캣 컨테이너가 시작될 때 웹 애플리케이션도 초기화되고, 톰캣 컨테이너가 종료될 때 웹애플리케이션도 제거된다. ServletContextListener API를 사용하면 언제 초기화되고 제거 되는지를 쉽게 알 수 있다.
ex) JDBC Pooling - 웹 애플리케이션이 초기화될 때 Pooling을 활성화하고, 제거될 때 비활성화 시키면 효율적인 Connection 관리를 할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@WebListener
public class ContextListener implements ServletContextListener {
    
    @Override
    public void contextDestroyed(ServletContextEvent e) {
        System.out.println("웹 애플리케이션 종료");
    }
 
    @Override
    public void contextInitialized(ServletContextEvent e) {
        System.out.println("웹 애플리케이션 초기화");        
    }
 
}
cs

Filter API
클라이언트인 웹 브라우저와 웹 서버인 서블릿은 요청과 응답을 주고 받는다. Filter API를 사용하면 웹 브라우저에서 서블릿으로의 요청 전에 선처리와
서블릿에서 웹 브라우저로의 응답 전에 후처리가 가능하다. 또한, 다수의 필터를 체인처럼 묶어서 적용할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
@WebFilter(urlPatterns = "/*")
public class AnnoFilter implements Filter {
 
    @Override
    public void destroy() {
        System.out.println("필터 제거");
    }
 
    @Override
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
            throws IOException, ServletException {
        System.out.println("선처리 요청필터");
        req.setCharacterEncoding("UTF-8");
        
        chain.doFilter(req, resp); // 선.후처리 기준점
        
        System.out.println("후처리 응답필터");
        resp.setCharacterEncoding("UTF-8");
    }
 
    @Override
    public void init(FilterConfig config) throws ServletException {
        System.out.println("필터 초기화");
    }
    
}
cs


서블릿 한글 깨짐 방지


HTML에서 입력한 파라미터 값에 한글이 포함되어 있다면 한글 인코딩 작업을 해야한다.
브라우저에서 문자를 처리하는 방식과 서버에서 문자를 처리하는 방식이 일치해야 한글이 깨지지 않는다.
톰캣서버의 기본문자 처리방식은 ISO-8859-1라서 한글 인식이 제대로 되지 않는다.

요청 방식에 따라 달리 처리해줘야 한다.
POST - 파라미터 값을 얻기전에 doGet 메소드에서 request.setCharacterEncoding("UTF-8"); 메소드로 한글 인코딩을 처리한다.
GET - 톰캣 설정 파일인 server.xml을 수정해야 한다. Connector 태그에 URIEncoding="UTF-8" 값을 추가해야 한다.
        8080포트로 직접 요청한 경우 
       <Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" URIEncoding="UTF-8"/>
        아파치에서 톰캣 커넥터를 통해 톰캣을 연결한 경우
        <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" URIEncoding="UTF-8"/>

어노테이션을 이용한 Servlet Project 시작하기


웹 프로젝트를 하기에 앞서 http://tomcat.apache.org 사이트에서 톰캣을 다운로드해 설치해야 한다. 또한 Java Enterprise Edition을 사용해야 한다.

어노테이션을 사용하기 위해 Dynamic Web Project를 생성할 때 웹 모듈 버전은 3.0 이상으로 설정한다.

'http://localhost:포트번호/컨텍스트명/맵핑명' 형식으로 요청하기 때문에 컨텍스트명은 생략해주는 것이 좋다. (server.xml에서 수정 가능하다.)

프로젝트 라이브러리에 톰캣이 안잡혔다면 다운로드 받은 톰캣의 lib 디렉토리에서 servlet-api.jar, jsp-api.jar 파일을 추가해줘야 한다.

간단한 요청을 구현하기 위해 Java Resources/src 경로에 서블릿 클래스를 생성한다.

1
2
3
4
5
6
7
8
9
10
@WebServlet("/hello")
public class HelloServlet extends HttpServlet {
    private static final long serialVersionUID = 1L;
       
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setCharacterEncoding("UTF-8");
        request.getRequestDispatcher("hello.jsp").include(request, response);
    }
    
}

cs

@WebServlet에 맵핑명을 지정한다. 배열로 여러개의 맵핑명을 지정할 수도 있다. (web.xml에 매핑하는 것보다 편하고 직관적이다.)
보여줄 페이지의 한글 깨짐을 방지하기 위해 인코딩방식을 UTF-8로 설정한다.
WebContent 하위 경로에 jsp 파일을 생성하고 해당 경로로 매핑해준다.

그리고 톰캣으로 Run하게되면 Servers 탭에 톰캣이 추가되고 더블클릭하면 다음과 같은 화면이 나온다.
8080포트의 충돌을 방지하기 위해 포트번호를 변경해준다.

http://localhost:8090/hello URL을 요청하면 서블릿 요청을 거쳐 다음과 같이 hello.jsp 화면을 출력한다.


+ Recent posts