Annotation 기반 Bean 설정

 

- Annotation의 사용으로 설정파일을 간결화하고 객체 또는 메소드의 맵핑을 명확하게 할 수 있다.

- Java code로 설정을 하기 때문에 type safe하며, Spring이 빠르게 container를 설정하게 한다.

- Annotation이 클래스 (또는 메소드) 상단에 추가되면서 설정이 구성되기 때문에 클래스 파일만 보아도 어떤 스프링 설정이 적용된 클래스인지 한눈에 알 수 있다.

- 설정이 변경될 경우 Application code 클래스 파일까지 수정해 주어야 한다.

- 애노테이션을 이용한 의존성 주입 Field Injection, Setter Injection, Constructor Injection

 

애노테이션을 이용한 이용한 의존성 주입(Dependency Injection)

1) Field Injection

- 필드를 통한 의존성 주입

- 사용 예

public class Sample {
	@Autowired
    private Example example;
}

 

2) Setter Injection(수정한 주입)

- setter 메소드를 통한 의존성 주입

- 사용 예

public class Sample {
	private Example example;
    @Autowired
    public void setExample(Example example) {
    this.example = example;
    }
}

 

3) Constructor Injection(생성자 주입)

- 생성자를 통한 의존성 주입

- 권장 방식

- 사용 예

public class Sample {
	private Example example;
    @Autowired
    public Sample(Example example) {
    	this.example = example;
    }
}

 

<context:annotation-config/>

- 애노테이션(Annotation)은 기본적으로 활성화되지 않기 때문에 xml에 명시적인 활성화 작업이 필요하다.

- Application Context 안에 이미 등록된 bean들의 Annotation을 활성화 하기 위해 사용 한다.

즉, 스프링 컨텍스트에 의해 생성되어 저장된 bean들에 대해서 @Autowired와 @Qualifier 등의 Annotation 을 인식할 수 있다.

- <context:component-scan> 은 Bean을 등록하고 @Autowired와 @Qualifier 등의 Annotation을 활성화 할 수 있지만 <context:annotation-config/>는 Bean을 등록하지는 못한다.

- <context:annotation-config/> 로 활성화 할 수 있는 Annotation

@Autowired, @Qualifier, @Resource, @PostConstruct, @PreDestroy 등

 

의존성 주입 애노테이션

1) @Autowired

- @Autowired는 주입하려고 하는 객체의 타입이 일치하는 객체를 자동으로 주입한다.

- @Autowired는 필드, 생성자, Setter 메소드, 일반 메소드에 붙일 수 있다.

- 필드에 붙이면 Setter를 통해 주입되며, Setter가 없으면 컴파일 과정에서 자동으로 추가된다.

- @Autowired를 필드, Setter 메소드에 붙여서 사용할 경우 반드시 기존 생성자가 정의되어 있어야 한다.

 

2) @Qualifier

- 동일한 타입한 타입의 빈 객체가 여러 개 정의되어 있는 경우 특정 빈을 주입할 수 있도록 설정한다.

@Qualifier는 <bean> 태그 하위에 <qualifier> 태그를 설정하여 특정 빈을 삽입할 수 있게 설정한다.

- @Autowired 애노테이션이 적용된 주입 대상에 @Qualifier 애노테이션을 설정한다.

@Qualifier는 단독으로 사용할 수 없으며 @Autowired애노테이션과 함께 사용한다.

- 형식

 @Autowired

 @Qualifier("beanName")

 

3) @Resource

- @Resource는 주입하려고 하는 객체의 이름<id>이 일치하는 객체를 자동으로 주입한다.

- @Resource는 Java제공 애노테이션이며 필드, 입력 파라미터가 하나인 Setter 메소드에 붙일 수 있다. 생성자에는 붙일 수 없다.

- 필드에 직접 정의하는 경우 Setter를 정의하지 않아도 된다.

- @Autowired와 마찬가지 반드시 기본 생성자가 정의되어 있어야 한다.

- 형식

 name 속성을 지정하지 않은 경우 : 필드명과 동일한 이름의 빈을 주입한다.

@Resource

 name 속성을 지정한 경우 : name 속성의 빈 이름과 동일한 빈을 주입한다.

@Resource(name="beanName")

 

4) @Inject

- @Inject는 @Autowired와 유사하며, 주입하려고 하는 객체의 타입이 일치한 객체를 자동으로 주입한다.

- @Inject는 Java 제공 애노테이션이며 필드, 생성자, Setter에 붙일 수 있다.

- @Inject를 사용하기 위해서는 javax.inject의존성을 추가한다.

 

5) @Named

- @Autowired의 @Qualifier와 같이 사용할 수 있는 것이 @Inject에서는 @Named 이다.

- @Named에 빈 이름(id)를 지정한다.

- 형식

 @Named("beanName")

 

기타 의존성주입 관련 애노테이션

1) @Required

 - setter에 붙여 반드시 주입 해야하는 프로퍼티로 설정하는 애노테이션

- Spring 5.1 버전부터 Deprecated 되었다. 반드시 주입해야 할 프로퍼티는 생성자 주입을 이용한다.

- 스프링 5.1이상을 사용하거나 자바 파일 bean을 등록했을 경우 무시된다.

 

2) @Value

- 기본 자료형과 문자열의 값을 필드에 주입하기 위해 사용되며, 필드나 생성자와 메소드는 매개 변수 수준에서 적용할 수 있다.

- 생성자 주입 시 자동으로 주입되지 않는 기본 자료형과 문자열의 값을 설정한다.

- 사용 예 : 생성자

public class Sample {
	private int num;
    @Autowired
    public Sample(@Value("10") int num) {
    	this.num = num;
    }
}

 

<context:component-scan/>태그

1) 개요

- Component Scan을 지원하는 태그

- Bean이 될 수 있는 모든 Componenet를 자동으로 찾아 Bean Container에 등록한다.

- 설정 과정을 XML로 선언하는 방식보다 이해하기 쉽고 직관적이다. 

 @Component, @Repository, @Service, @Controller를 선언하고자 하는 Java 코드에 용도에 맞게 직관적으로 선언을 하기 때문에 알아보기 쉽고, 코드를 이해하기도 편하다.

- <context:component-scan>을 이용하게 되면 <context:annotation-config>의 사용이 불필요하다. 즉, @Autowired, @Qualifier, @Resource 같은 애노테이션도 활성화되므로 사용이 불필요하다.

 

컨테이너(Container) 란?

- 컨테이너는 어플리케이션을 관련 라이브러리 및 종속항목과 함께 패키지로 묶어 소프트웨어 서비스 구동을 위한 격리 환경을 제공한다.

- 컨테이너는 보통 인스턴스의 생명주기 관리와 추가적인 기능을 제공한다.

  Servlet 컨테이너는 Servlet의 생성, 생성 후 초기화, 서비스 실행, 소멸에 관한 모든 권한을 가지고 있다.

  개발자가 직접 Servlet을 생성하고 서비스하지는 않는다.

- 스프링 컨테이너는 스프링 프레임워크의 핵심부에 위치하며, 종속객체 주입을 이용하여 애플리케이션을 구성하는 컴포넌트들을 관리한다. 

 

IoC(Inversion Of Control, 제어의 역전)란?

- IoC는 객체의 생성, 생명주기의 관리까지 모든 객체에 대한 제어권이 바뀌었다는 것을 의미한다.

즉, 인스턴스 생성에서 소멸까지의 생명주기 관리를 개발자가 아닌 컨테리너가 담당한다는 것을 의미한다.

- 컴포넌트 의존관계 결정(Component Dependency Resolution), 설정(configuration) 및 생명주기(lifecycle)를 해결하기 위한 디자인 패턴(Design Pattern)이다.

- IoC는 객체 간의 결합도를 줄이고 유연한 코드를 작성하게 하여 가독성 및 코드의 중복, 유지보수를 편하게 할 수 있다.

 

IoC 구현 방법

- DL (Dependency Lookup, 의존성 검색)

저장소에 저장되어 있는 Bean에 접근하기 위해 컨테이너가 제공하는 API를 이용하여 Bean을 Lookup

EJB, Spring 등에서 지원

- DI (Dependency Injection, 의존성 주입)

각 클래스간의 의존관계를 빈 설정(Bean Definition) 정보를 바탕으로 컨테이너가 자동으로 연결한다.

Constructor Injection, Method(Setter) Injection, Field Injection 등

- Spring, PicoContainer 에서 지원

 

Dependency Injection(의존성 주입)

- 객체 자체가 아니라 Framework에 의해 객체의 의존성이 주입되는 설계 패턴

각 클래스간의 의존관계를 빈 설정(Bean Definition) 정보를 바탕으로 컨테이너가 자동으로 연결

- Framework에 의해 동적으로 주입되므로 모듈 간의 결합도가 낮아지고 유연성이 높아진다.

- Dependency Injection은 Spring Framework에서 지원하는 IoC의 형태

- 의존성 주입 방법

Constructor Injection : 생성자를 이용한 의존성 주입

Method(Setter) Injection : Setter나 일반 메소드를 이용한 의존성 주입

Field Injection : 필드를 통한 의존성 주입

 

 

Dependency Injection(의존성 주입) 장점

- Dependency Reduction : 객체 상호 간 의존성 관계를 줄여준다.

- Reusable Structure : 코드의 재사용과 조합이 용이하다.

- Readability : 코드들이 분리되어 가독성이 높다.

- Loose Coupling & Easy to change : 구조는 변화에 민감하지 않을 수 있다.

- 기타 테스트가 용이하고 다양한 패턴을 적용하는 데 유연하다.

 

<?xml version="1.0" encoding="UTF-8"?>  
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:p="http://www.springframework.org/schema/p"
	xmlns:util="http://www.springframework.org/schema/util"
	xmlns:task="http://www.springframework.org/schema/task"
	xsi:schemaLocation="
	    http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
		http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd
        http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd">
		
	<!-- bean 태그 : 스프링 컨테이너에 빈을 정의(객체 생성) -->
	<!-- 기본 생성자를 이용하여 빈을 정의 -->
	<bean id="userService" class="com.user1.UserServiceImpl"/>
	
	<!-- 생성자로 기본 자료형의 값을 인수로 전달 -->
<!-- 
	<bean id="userService2" class="com.user1.UserServiceImpl2">
		<constructor-arg value="이자바"/>
		<constructor-arg value="010-1111-1111"/> 
		<constructor-arg value="17"/>
	</bean>
-->	
	<bean id="userService2" class="com.user1.UserServiceImpl2">
		<constructor-arg index="0" value="이자바"/>
		<constructor-arg index="2" value="17"/>
		<constructor-arg index="1" value="010-1111-1111"/>
	</bean>

	<!-- 생성자를 이용한 의존성 주입 -->
	<bean id="user" class="com.user1.User">
		<constructor-arg ref="userService2"/>
	</bean>
	
</beans>
<!-- c 네임스페이스를 이용하여 생성자에 값 설정(문자열 또는 기본 자료형) -->
	<bean id="userService2" class="com.user2.UserServiceImpl2"
		c:name="너자바" c:tel="010-2222-2222" c:age="23"/>
	
	<!-- c 네임스페이스를 이용하여 생성자로 의존성 주입 -->
	<!-- init-method : 메소드 설정 - 객체가 생성될 때 단 한 번 호출(초기화 작업이 필요한 경우) -->
	<!-- destroy=method : 메소드 설정 - 객체가 소멸되기 직전 한 번 호출 -->
	<bean id="user" class="com.user2.User"
		c:userService-ref="userService2"
		init-method="init"
		destroy-method="destroy"/>
	<bean id="userService" class="com.user3.UserServiceImpl"/>
	
	<!-- setter를 이용한 프로퍼티 설정(문자열 또는 기본자료형) -->
	<bean id="userService2" class="com.user3.UserServiceImpl2">
		<property name="name" value="다자바"/>
		<property name="tel" value="010-5555-5555"/>
		<property name="age" value="21"/>
	</bean>
	
	<!-- setter를 이용한 의존성 주입 -->
	<!-- 반드시 setter가 존재해야함 -->
	<!-- setter는 name 속성값을 기준으로 첫글자를 대문자로하여 앞에 set을 붙인 메소드명 -->
	<!-- name="userService" => setUserService 라는 메소드명이 존재해야 함 -->
	<bean id="user" class="com.user3.User">
		<property name="userService" ref="userService2"/>
	</bean>
<bean id="userService" class="com.user4.UserServiceImpl"/>
	
	<!-- p 네임스페이스를 이용한 프로퍼티 설정(문자열 또는 기본자료형) -->
	<bean id="userService2" class="com.user4.UserServiceImpl2"
		p:name="홍자바" p:tel="010-1234-5678" p:age="20"/>
	
	<!-- setter를 이용한 의존성 주입 (p 네임스페이스) -->
	<!-- 반드시 setter가 존재해야함 -->
	<bean id="user" class="com.user4.User"
		p:userService-ref="userService2"/>
	<bean id="userService" class="com.user5.UserServiceImpl">
		<property name="name" value="컬렉션"/>
		<property name="address">
			<map>
				<entry key="서블릿" value="서울"/> <!-- <entry key-ref="객체명-1" value-ref="객체명-2"/> -->
				<entry>
					<key><value>스프링</value></key>
					<value>경기</value> <!-- <ref bean="객체명"/> -->
				</entry>
			</map>
		</property>
		<property name="hobby">
			<list>
				<value>게임</value> <!-- <ref bean="객체명"/> -->
				<value>영화</value>
				<value>음악</value>
			</list>
		</property>
		<property name="tels">
			<props>
				<prop key="후후후">010-1111-1111</prop>
				<prop key="호호호">010-2222-2222</prop>
				<prop key="하하하">010-3333-3333</prop>
			</props>
		</property>
	</bean>
	
	<bean id="user" class="com.user5.User">
		<property name="userService" ref="userService"/>
	</bean>
<!-- properties 파일  읽기 -->
	<context:property-placeholder 
		location="classpath:com/user6/user.properties"/>
	
	<bean id="userService" class="com.user6.UserServiceImpl">
		<property name="name" value="${join.name}"/>
		<property name="tel" value="${join.tel}"/>
		<property name="age" value="${join.age}"/>
	</bean>
	
	<bean id="user" class="com.user6.User">
		<property name="userService" ref="userService"/>
	</bean>
<!-- scope : 기본 - singleton : 하나의 객체만 생성 -->
	<bean id="movie" class="com.scope1.Movie"/>
	
	<!-- prototype : 객체를 호출할 때 마다 새로운 객체 생성 -->
	<bean id="music" class="com.scope1.Music" scope="prototype"/>

<bean id="movie" class="com.scope2.Movie" scope="prototype"/>
	<bean id="music" class="com.scope2.Music" scope="prototype">
		<aop:scoped-proxy/> <!-- 메소드를 호출할 때 마다 객체가 생성 -->
	</bean>
	
	<bean id="user" class="com.scope2.User">
		<property name="movie" ref="movie"/>
		<property name="music" ref="music"/>
	</bean>

<!-- scope : 기본 - singleton : 하나의 객체만 생성 -->
<!-- scope="prototype" - 빈을 호출 할 때마다 새로운 객체를 생성 -->	

<!-- 피자 -->
<bean id="pizza" class="com.look.Pizza" scope="prototype"/>

<!-- 베지 피자 -->
<bean id="veggiePizza" class="com.look.Pizza" scope="prototype">
	<property name="isVeg" value="true"/>
</bean>

<!-- 
	룩업 메소드 인젝션 : 컨테이너가 관리하는 빈의 메소드를 재정의하여
					컨테이너 안의 다른 빈을 검색하는 기능 
 -->
<bean id="pizzaShop" class="com.look.PizzaShop">
	<lookup-method name="makePizza" bean="pizza"/>
	<lookup-method name="makeVeggiePizza" bean="veggiePizza"/>
</bean>

 

프레임워크(Framework) 란?

소프트웨어의 구체적인 부분에 해당하는 설계와 구현을 재사용이 가능하게끔 일련의 협업화된 형태로 클래스들을 제공하는 것

즉, 복잡한 문제를 해결하거나 서술하는데 사용되는 기본 개념 구조(뼈대) 이다.

프레임워크는 라이브러리와 달리 애플리케이션의 틀과 구저를 결정할 뿐 아니라, 그 위에 개발된 개발자의 코드를 제어한다.

프레임 워크는 구체적이며 확장 가능한 기반 코드를 가지고 있으며, 설계자가 의도하는 여러 디자인 패턴의 집합으로 구성되어 있다.

 

라이브러리(Library)란 ?

자주 사용되는 로직을 재사용하기 편리하도록 잘 정리한 일련의 코드들의 집합

소프트웨어 개발 시 사용되는 프로그램의 구성요소로, 공통으로 상요될 수 있는 특정한 기능(들)을 모듈화한 것

대상 환경(플랫폼)에서 바로 실행될 수 있는 형태로 제공

라이브러리 자체로는 사용자가 직접 일반적인조작으로실행할 수 없으며, 해당 라이브러리의 기능을 직접 호출하는 프로그램을 실행하거나, 사용자가 해당 라이브러리의 기능을 실행하는 API를 사용하는 프로그램을 직접 개발하여 실행

프로그래밍 언어에서 라이브러리를 사용할 수 있도록 소스코드 수준에서 인터페이스를 노출시킨 것이 API이다.

 

스프링 프레임워크란?

자바엔터프라이즈 개발을 위한 오픈 소스 애플리케이션 프레임워크

자바 객체를 담고 있는 경량의 컨테이너로서 자바 객체의 생성, 소멸과 같은 라이프 사이클을 관리

DI(Dependency injextion), AOP(Aspect Oriented Programming), MVC(Model View Controller), 트랜잭션, 보안 등의 기능을 지원

Spring Framework는 IoC(Inversion of Control, 제어의 역전) 기반이다. 컨트롤의 제어권이 사용자가 아니라 프레임워크에 있어 필요에ㅜ 따라 스프링에서 사용자의 코드를 호출한다.

제어의 역전(IoC : Inversion of Control) ?

- 일반적인 프로그램은 객체의 생성 및 소면, 의존성 주입, 메소드 호출 등을 개발자가 제어하는 구조이다. 하지만, 기존 개발자가 모든 작업을 제어하던 것을 특별한 객체에 모든 것을 위임하여 객체의 생성부터 소멸까지의 생명주기, 의존성 주입 등 모든 객체에 대한 제어권이 넘어간 것을  IoC(제어의 역전)라 한다. 

 

특징

- 컨테이너 역할 : Spring 컨테이너는 객체의 LifeCycle을 관리하며, 컨테이너로부터 필요한 객체를 가져와 사용할 수 있다.

- 의존성 주입(DI : dependency Injection) : Spring은 설정파일이나 어노테이션을 통해서 객체 간의 의존관계를 설정한다.

- 관점지향 프로그래밍(AOP : Aspect-Oriented Programming) : 트랜잭션이나 로깅, 보안과 같이 여러 모듈에서 공통적으로 사용하는 기능의 경우 해당 기능을 분리하여 관리

- 트랜잭션 처리를 위한 일관된 방법 제공 : JDBC, JTA(JavaTransaction API) 등 어떤 트랜잭션을 사용하던 설정을 통해 정보를 관리하므로 트랜잭션 구현에 상관없이 동일한 코드 사용가능

- 영속성과 관련된 다양한 API를 지원 : JDBC 및 MyBatis, Hibernate, JPA(Java Persistence API) 등 데이터베이스 처리를 위한 ORM(Object Relational Mapping) 프레임워크와의 연동을 지원

- POJO(Plain Old Vaca Object) 지원 : 컨테이너에 저장되는 Java 객체는 특정한 인터페이스를 구현하거나, 특정 클래스를 상속받지 않아도 된다.

 

POJO(Plain Old Java Object)

- POJO란 객체지향적인 원리에 충실하면서, 특정 환경과 규약에 종속되지 않아 필요에 따라 재사용될 수 있는 방식으로 설계된 오브젝트라 할 수 있다.

- 조건

(1) 특정 규약에 종속되지 않는다.

- 지정된 클래스를 extends 하지 않는다.

- 정의된 인터페이스를 implement 하지 않는다.

- 정의된 Annotation을 포함하지 않는다.

- 특정 규약에 종속되지 않아 객체지향 설계가 용이하다.

(2) 특정 환경에 종속되지 않는다.

- 예를 들어 웹 환경에 종속되는 HttpServletRequest나 HttpSession과 관련된 API를 직접 이용하면 안된다.

- 다른 환경에서 사용하기 어려우며, 웹 서버 없이 독립적으로 테스트가 어렵다.

- 비지니스 로직과 기술적인 내용을 담은 웹 정보 코드가 섞여 이해하기 어려워진다.

(3) 단일 책임 원칙을 지키는 클래스

책임과 역할이 각기 다른 코드를 하나의 클래스에 넣는 경우 진정한 POJO라 할 수 없다.

 

 

Spring Framework의 구조

- Spring Core

Spring Core는 Spring Container을 의미하며 Spring Framework의 핵심이다.

- Spring Context

 context정보들을 제공하는 설정 파일로, JNDI, EJB, Validation, Scheduling, Internalization 등의 서비스

- Spring AOP(Aspect-Oriented Programming, 관점 지향 프로그래밍)

 공통의 관심 사항을 적용해서 발생하는 의존 관계의 복잡성과 코드 중복을 해소해 주는 프로그래밍 기법

- Spring DAO(Data Access Object)

 JDBC 추상화계층을 제공하여 코드나 예외처리부분을 간편화 시켜 일관된 방법

- Spring ORM(Object Relational Mapping)

Hibernate, JPA(Java Persistence API), JDO(java Data Objects), MyBatis 등을 지원

- Spring Web

 일반적인 Web Application 개발에 필요한 기본적인 기능을 지원

- Spring MVC(Model-View-Controller)

Model2 구조로 Application을 만들 수 있도록 지원

개발 환경
  - J2SE
    JDK 8 Update 291
  - DBMS
    Oracle 18c
  - WAS(Web Container)
    Apache Tomcat 8.5
  - Servlet/JSP Spec
    Servlet 3.1 / JSP 2.3
  - 소프트웨어 형상관리(Software Configuration Management)
    GIT
  - 기타
    javascript, AJAX, JSON, jQuery, CSS3, HTML5 

 

JSP/Servlet으로 이번에는 UI도 만들어서 웹 프로그래밍을 팀플로 진행해보았다 :) 기능을 만들 때 생각처럼 되지 않는 것들도 있었지만 어쨌든 팀원들과 함께 프로젝트를 완성해서 뜻깊은 경험이었다.!

 

죽어도 value 값을 안가져와서 .. 왜 그런가 했더니

$(function() {
	
	$("body").on("click", "#toCartBtn", function() {
		
		if(! $("#colorBox option:selected").val() ){
			alert("컬러를 선택하세요.");
			return;
		}
		
		if(! $("#sizeBox option:selected").val() ){
			alert("사이즈를 선택하세요.");
			return;
		}
		
	});
	
});
<form name="form" method="post">
			<select class="selectbox" id="colorBox">
				<option value="">::컬러::</option>
				<c:forEach var="dto" items="${colorList}" varStatus="status">
					<option value="${dto.ccnum}">${dto.color}</option>
				</c:forEach>
			</select>
			<select class="selectbox" id="sizeBox">
				<option>::사이즈::</option>
			</select><br>
				<input type="text" class="amount" name="amount" value="1" onchange="change()">
				<input type="button" value=" + " onclick="add();">
				<input type="button" value=" - " onclick="del();"><br>
			
			<div class = "total">
			Total<br>
				<input id="totalPrice" type="text" name="sum" size="11" readonly="readonly" value="${dto.price}">₩<br><br>
				<input class="btn" id="buyBtn" type="text" value = "Buy Now" onclick="buyNow()">
				<input class="btn" id="toCartBtn" type="text"  value = "Add To Cart" onclick="addCart()">
			</div>
			
			<div class="detail-add">
				<c:if test="${sessionScope.member.userId=='admin'}">
					<button type="button" class="btn btn1" onclick="location.href='${pageContext.request.contextPath}/shop/garment-detail.do?num=${dto.cnum}&page=${page}';">색상/사이즈 관리</button>
				</c:if>
			</div>
		</form>

제일 위에 있는 <option>::컬러::</option> 여기에 value="" 를 안쓰면 죽어도 안된다ㅠ

 

꼭 value="" 이렇게 해야 한다!!

커스텀 태그(Custom Tag, 사용자 정의 태그) 이해

 

커스텀 태그(Custom Tag, 사용자 정의 태그)란?

- JSP 언어의 확장인 커스텀 태그는 동적 기능을 캡슐화하는 메커니즘을 제공한다.

- 커스텀 태그는 사용자 정의 JSP 요소로 특정 작업을 수행하기 위하여 사용자에 의해 만들어진 태그이다.

- JSTL도 커스텀 태그의 일정으로 JSP 페이지 개발 및 유지 관리를 단순화한다.

 

커스텀 태그 장점

- 재 사용성 향상 : 한번 작성한 커스텀 태그는 어떤 JSP 컨테이너에서든지 사용 가능하다.

- 쉽고 단순한 JSP 제작 : 자바 코드에 익숙하지 않은 개발자들도 커스텀 태그를 통해서 쉽게 JSP 페이지를 작성할 수 있게 된다.

- 코드의 가독성 향상 : 스크립트 코드를 줄일 수 있기 때문에 JSP 코드의 가독성을 높일 수 있다.

 

커스텀 태그 종류

- JSP 1.2 기반의 커스텀 태그

- JSP 2.0 또는 그 이상 버전의 SimpleTag를 사용한 커스텀 태그

- JSP 2.0 또는 그 이상 버전의 태그 파일을 사용한 커스텀 태그

 

커스텀 태그 관련 인터페이스

javax.servlet.jsp.tagext_JspTag 인터페이스 

- 선언된 메소드는 없으며, Tag 및 SimpleTag 인터페이스의 상위 인터페이스이다.

 

javax.servlet.jsp.tagext.Tag 인터페이스

- JSP 1.2에서 제공하는 커스텀 태그를 구현할 경우에 사용한다.

- 단순한 태그 처리 시 사용하는 커스텀 태그이다.

- JspTag 인터페이스를 상속받았다.

 

javax.servlet.jsp.tagext.IterationTag 인터페이스

- JSP 1.2에서 제공하는 커스텀 태그

- 반복적인 작업을 처리하는 커스텀 태그이다.

- JspTag, Tag 인터페이스를 상속받앙ㅆ다.

 

javax.servlet.jsp.tagext.BodyTag 인터페이스

- JSP 1.2에서 제공하는 커스텀 태그를 구현할 경우에 사용한다.

- 태그의 body 내용이 있을 때 사용하는 커스텀 태그이다.

- InterationTag, JspTag, Tag 인터페이스를 상속 받았다.

 

JSP 1.2 기반 커스텀 태그 관련 인터페이스 및 클래스

javax.servlet.jsp.tagext.JspTag 인터페이스

- 선언된 메소드는 없으며, Tag 및 SimpleTag 인터페이스의 상위 인터페이스이다.

 

javax.servlet.jsp.tagext.Tag 인터페이스

- JSP 1.2에서 제공하는 커스텀 태그를 구현할 경우에 사용한다.

- 단순한 태그 처리 시 사용하는 커스텀 태그이다.

- JspTag 인터페이스를 상속받았다.

 

javax.servlet.jsp.tagext.IterationTag 인터페이스

- JSP 1.2에서 제공하는 커스텀 태그를 구현할 경우에 사용한다.

- 반복적인 작업을 처리하는 커스텀 태그이다.

- JspTag, Tag 인터페이스를 상속받았다.

 

javax.servlet.tagext.BodyTag 인터페이스

- JSP 1.2에서 제공하는 커스텀 태그를 구현할 경우에 사용한다.

- 태그의 body 내용이 있을 때 사용하는 커스텀 태그이다.

- IterationTag, JspTag, Tag 인터페이스를 상속받았다.

 

javax.servlet.jsp.tagext.TagSupport 클래스

- 커스텀 태그를 구현하기 위한 클래스의 최상위 클래스이다.

- IterationTag, JspTag, Tag 인터페이스를 구현한 클래스이다.

 

javax.servlet.jsp.tagext.BodyTagSupport 클래스

- 몸체(body)가 있는 커스텀 태그를 구현하기 위한 클래스의 상위 클래스이다.

- TagSupport 클래스의 하위 클래스이다.

- BodyTag, IterationTag, JspTag, Tag 인터페이스를 구현한 클래스이다.

 

JSP 2.0 기반 커스텀 태그 관련 인터페이스 및 클래스

 

javax.servlet.jsp.tagext.SimpleTag 인터페이스

- JSP 2.0 에서 제공하는 커스텀 태그 구현 시 사용한다.

- Tag, IterationTag 를 하나로 묶어서 좀 더 쉽게 구현이 가능한 커스텀 태그이다.

- JspTag 인터페이스를 상속 받았다.

 

javax.servlet.jsp.tagext.SimpleTagSupport 클래스

- SimpleTag를 구현하는 태그 핸들러를 정의하기 위한 상위 클래스이다.

- SimpleTag 인터페이스를 구현한 클래스이다.

 

javax.servlet.jsp.tagext.DynamicAttributes 

- 커스텀 태그가 동적 속성을 처리하기 위해서는 이 인터페이스를 구현해야 한다.

 

 

 

필터(filter)이해

 

필터란 ?

- 필터는 클라이언트 요청의 사전 처리 및 후 처리에 호출되는 객체로 요청을 변환하거나, 응답을 변경하는 기능을 수행한다.

- 필터는 주로, 인증, 로깅, 데이터 압축이나 변환, 요청 암호화 및 암호 해독, 입력 유효성 검사 등과 같은 필터링 작업을 수행하는 데 사용된다.

- 하나의 서블릿이나 JSP에 대한 요청이나 응답을 수정해야 하는 경우에는 필터를 만들 필요가 없으며, 여러 개의 서블릿에 대한 요청 및 응답에 사전 처리 또는 사후 처리를 적용하려는 경우에 작성한다.

- request 필터 : 요청(Request)이 백엔드(back end)의 자원(Servlet, JSP 등)에 도달하기 전에 필요한 전 처리를 한다.

- response 필터 : 서버에서 요청(Request)에 대한 처리를 한 후, 클라이언트에 응답(Response)하기 전에 후 처리를 한다.

- 필터들을 여러 개 사용 하면 연쇄적으로 사용할 수도 있다.

 

용도

- request 필터

: 인증 - 사용자 ID를 기반으로 요청을 차단

: 로깅 및 감사 - 웹 응용 프로그램의 사용자 추적(요청정보를 로그파일로 작성)

: 인코딩 작업 등

 

- response 필터

: 데이터 압축 - 다운로드 크기를 줄인다.

: XML 컨텐츠의 XSL/T 변환 (XSL/T : XML 문서를 다른 XML 문서로 변환하는데 사용하는 XML 기반 언어

: 총 서비스 시간측정 등

 

필터(filter) 관련 클래스 및 인터페이스

javax.servlet.Filter 인터페이스

- 필터 클래스는 javax.servlet.Filter 인터페이스를 구현하여 작성한다.

- 필터는 doFilter() 메소드에서 필터링을 수행한다.

- 모든 필터는 초기화 매개 변수를 얻을 수 있는 FilterConfig 객체에 액세스 할 수 있다.

 

javax.servlet.FilterChain 인터페이스 

- FilterChain은 자원에 대한 필터링된 요청의 호출 체인에 대한 뷰를 제공하는 개발자에게 서블릿 컨테이너가 제공하는 객체이다.

- 필터는 FilterChain을 사용하여 체인의 다음 필터를 호출하거나 호출하는 필터가 체인의 마지막 필터인 경우 체인의 끝에 있는 리소스를 호출한다. 

 

javax.servlet.ServletRequestWrapper 클래스

- ServletRequestWrapper 클래스는 ServletRequest 인터페이스에 정의된 모든 메소드를 구현한 클래스

- javax.servlet.http 패키지에 정의된 HttpServletRequestWrapper 클래스는 HttpServletRequest 인터페이스에 정의된 모든 메소드를 구현한 클래스

- ServletRequestWrapper와 HttpServletRequestWrapper 클래스의 메소드 중 변경해야 하는 메소드를 재정의하여 구현하고 필터의 doFilter() 메소드에 넘겨주면, 클라이언트의 요청 정보를 변경할 수 있는 래퍼 클래스이다.

 

javax.servlet.ServletResponseWrapper 클래스

- ServletResponseWrapper 클래스는 ServletResponse 인터페이스에 정의된 모든 메소드를 구현한 클래스

- javax.servlet.http 패키지에 정의된 HttpServletResponseWrapper 클래스는 HttpServletResponse 인터페이스에 정의된 모든 메소드를 구현한 클래스

- ServletResponseWrapper와 HttpServletResponseWrapper 클래스의 메소드 중 변경해야 하는 메소드를 재정의하여 구현하고 필터의 doFilter() 메소드에 넘겨주면, 응답 결과를 변경할 수 있는 wrapper 클래스이다.

 

필터(filter) 설정

형식 - 1 : web.xml 에서 설정

- 필터 인터페이스를 구현한 클래스를 작성한 후 서블릿 컨테이너가 필터를 찾아서 호출할 수 있도록 웹 애플리케이션 배포 기술자 파일(web.xml)에 필터를 등록한다.

<web-app ...>
	:
    <filter>
    	<filter-name>필터이름</filter-name>
        <filter-class>패키지명을 포함한 필터클래스 명</filter-class>
        [<init-param>
        	<param-name>파라미터이름</param-name>
            <param-value>파라미터값</param-value>
        </init-param>]
    </filter>
    <filter-mapping>
    	<filter-name>필터이름</filter-name>
        <url-pattern>경로패턴</url-pattern>
    </filter-mapping>
    :
</web-app>

 

형식 - 2 : @WebFilter Annotation으로 설정

- Servlet 3.0부터 제공되는 Annotation으로 필터 처리를 위한 필터 객체를 등록 한다.

- web.xml의 관련 태그 : <filter>, <filter-mapping>

@WebFilter(
	attribute1=value1,
    attribute2=value2,
    ...
)

	public class TheFilter implements favax.servlet.Filter {
    	// implements Filter's methods
    }

 

 

package com.filter;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;

@WebFilter("/*")
public class TimerFilter implements Filter{
	private FilterConfig filterConfig;
	
	@Override
	public void init(FilterConfig filterConfig) throws ServletException {
		// 필터클래스의 객체가 생성될 때 한번 실행
		
		this.filterConfig = filterConfig;
	}
	
	@Override
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
			throws IOException, ServletException {
		// 클라이언트의 요청이 있을때마다 실행
		
		// request 필터
		long begin = System.currentTimeMillis();
		
		// 다음 필터 또는 필터의 마지막이면 end-pointer(jsp, 서블릿)를 실행
		chain.doFilter(request, response);
		
		// response 필터
		long after =System.currentTimeMillis();
		
		String uri = "";
		if(request instanceof HttpServletRequest) {
			HttpServletRequest req = (HttpServletRequest)request;
			
			uri = req.getRequestURI();
			filterConfig.getServletContext().log(uri + " : " + (after - begin) + "ms");
		}
	}

	@Override
	public void destroy() {
		// 필터 클래스의 객체가 파괴될 때 한 번 실행
		
	}
	
}

 

위를 사용해서

콘솔 창에 응답시간을 찍을 수 있다. 

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
<link rel="icon" href="data:;base64,iVBORw0KGgo=">
<style type="text/css">
*{
	padding: 0; margin: 0;
}

body {
    font-size:14px;
	font-family:"맑은 고딕", 나눔고딕, 돋움, sans-serif;
}

a {
	color: #000;
	text-decoration: none;
}
a:hover, a:active {
	color: tomato;
	text-decoration: underline;
}

.btn {
    color:#333;
    font-weight:500;
    border:1px solid #cccc;
    background-color:#fff;
    text-align:center;
    cursor:pointer;
    padding:3px 10px 5px;
    border-radius:4px;
}
.btn:active, .btn:focus, .btn:hover {
	 background-color:#e6e6e6;
	 border-color: #adadad;
	 color: #333;
}
.boxTF {
    border:1px solid #999;
    padding:4px 5px 5px;
    border-radius:4px;
    background-color:#fff;
}
.boxTA {
    border:1px solid #999;
    height:150px;
    padding:3px 5px;
    border-radius:4px;
    background-color:#fff;
    resize: none;
}

textarea:focus, input:focus {
	outline: none;
}

h3 {
	margin: 10px;
}

.box{
	width: 650px;
	margin: 30px auto;
}

.box table {
	width: 100%;
	border-collapse: collapse;
	border-spacing: 0;
}

.board-title {
	width:100%;
	height:50px;
	line-height:50px;
	text-align:left;
	font-weight: bold;
	font-size:15px;
}

.board-body tr:first-child{
	border-top: 3px solid #777;
}
.board-body tr {
	height: 40px;
	border-bottom: 1px solid #777;
}
.board-body td:first-child{
	text-align: center;
	width: 100px;
	background: #eee;
}

</style>

<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script type="text/javascript">
function sendOk() {
	var f = document.boardForm;
	
	// 유효성 검사
	var returnNow = false;
	var s;
	$("form input, form textarea").each(function() {
		if(! $(this).val().trim()) { // 공백까지 없애서 유효성 검사
			s = $(this).closest("tr").find("td:first-child").text();
			s = s.replace(/\s/g, '');
			
			alert(s + "을(를) 입력하세요 !!!");
			
			$(this).focus();
			returnNow = true;
			
			return false; // return false : each를 빠져나갈 수 있다. (break; 개념)
		}
	});
	
	if(returnNow) return;
	
	alert("보내기 성공...");
}
</script>

</head>
<body>

<h3>each - break 구현</h3>

<div class="box">
	<div class="board-title">
    	<h3><span>|</span> 게시판</h3>
	</div>
	
	<form name="boardForm" method="post">
	  <table class="board-body">
	  <tr> 
		  <td >제 목</td>
		  <td style="padding-left:10px;"> 
			<input type="text" name="subject" maxlength="100" class="boxTF" style="width: 97%;">
		  </td>
	  </tr>

	  <tr> 
		  <td>작성자</td>
		  <td style="padding-left:10px;"> 
			<input type="text" name="name" size="35" maxlength="20" class="boxTF">
		  </td>
	  </tr>

	  <tr> 
		  <td style="padding-top:5px;"  valign="top">내 용</td>
		  <td valign="top" style="padding:5px 0px 5px 10px;"> 
			<textarea name="content" cols="75" rows="12" class="boxTA" style="width: 97%;"></textarea>
		  </td>
	  </tr>

	  <tr>
		  <td>패스워드</td>
		  <td style="padding-left:10px;"> 
			   <input type="password" name="pwd" size="35" maxlength="7" class="boxTF">&nbsp;(게시물 수정 및 삭제시 필요 !!!)
		   </td>
	  </tr> 
	  </table>

	  <table>
		 <tr align="center"> 
		  <td height="45">
			  <button type="button" class="btn" onclick="sendOk();"> 등록하기 </button>
			  <button type="reset" class="btn"> 다시입력 </button>
			  <button type="button" class="btn"> 취소하기 </button>
		  </td>
		</tr>
	  </table>
	</form>
</div>

</body>
</html>

return false를 통해 each를 빠져나갈 수 있다.

+ Recent posts