Resource Interface 구현체
그래서 Spring은 필요한 기능을 만들어 따로 제공한다.
∙ URLResource
java.net.URL 을 래핑한 버전.
다양한 종류(ftp:,file:,http: 등의 prefix로 접근유형을 판단) 의 Resource에 접근 가능하지만 기본적으로는 http(s)로 원격접근
∙ ClassPathResource
classPath(소스코드를 빌드한 결과(기본적으로 target/classes폴더)) 하위의 리소스 접근 시 사용
∙ FileSystemResource
이름과 같이 file을 다루기 위한 리소스 구현체
∙ ServletContextResource,InputStreamResource,ByteArrayResource
servlet 어플리케이션 루트 하위 파일, InputStream,ByteArrayInput 스트림을 가져오기 위한 구현체
[예시]
public interface Resource extends InputStreamSource{
boolean exists();
boolean isReadable();
boolean isOpen();
boolean isFile();
URL getURL() throws IOExeption;
URI getURI() throws IOExeption;
File getFile() throws IOExeption;
ReadableByteChannel readableChannel() throws IOExeption;
long contentLength() throws IOExeption;
long lastModified() throws IOException;
Resource createRelative(String relativePath) throws IOException;
String getFilename();
String getDescription();
}
Spring ResourceLoader
기본적으로 applicationContext에 구현되어있음.
프로젝트 내 (주로 class path하위 파일)에 접근 할 때 사용
대부분의 사전정의 파일들은 자동로딩되나, 추가로 파일이 필요한 경우 사용.
public interface ResourceLoader {
Resource getResource(String location);
ClassLoader getClassLoader();
}
AOP 관점지향 프로그래밍
여러 메서드에서 동일한 코드가 반복된다? -> AOP 로 처리!
공통적인 관심사(로깅,트랜잭션,인증)를 여러 메서드의 호출 전/후에 원할때마다 추가
OOP로 처리하기 까다로운부분을 AOP처리하여 손쉽게 공통기능 추가/수정/삭제
AOP의 기본개념 | 설명 |
---|---|
Aspect | 여러클래스나 기능에 결쳐있는 관심사를 모듈화함. AOP중에서도 @Transactional(트랜색션관리),@Cacheable 기능 |
Advice | AOP에서 실제로 적용하는 기능을 뜻함(로깅,트랜잭션, 캐시 , 인증 등) |
Join Point | 모듈화된 특정 기능이 실행될 수 있는 연결포인트 |
Pointcut | Join Point중에서 해당 Aspect를 적용할 대상을 뽑을 조건식</span |
Target Object | Advice가 적용될 대상 Object |
AOP Proxy | 대상 Object에 Aspect를 적용하는 경우 Advice를 덧붙이기 위해 하는 작업 주로 CGLIB(실행 중 실시간 코드생성)프록시를 사용하여 처리 |
Weaving | Advice를 비즈니스 로직 코드에 삽입 |
AspectJ Library
Spring AOP로는 AOP 사용기법에 한계가 존재.
Aspect 생성
package org.xyz;
import org.aspectj.lang.annotation.Aspect;
@Aspect
@Component // 해당 Aspect를 Spring의 Bean으로 등록해 사용
public class UsefulAspect{
}
Pointcut 선언 및 결합
package org.xyz;
import org.aspectj.lang.annotation.Aspect;
@Aspect
@Component // 해당 Aspect를 Spring의 Bean으로 등록해 사용
public class UsefulAspect{
@Pointcut("execution(public **(..))") //모든 public 메서드 대상
private void anyPublicOperation(){}
@Pointcut("within(com.xyz.myapp.trading..*)") //특정 패키지 대상
private void inTrading(){}
@Pointcut("anyPublicOperation() && inTrading()")// 두 조건을 모두 만족하는 대상
private void tradingOperation(){}
}
Advice 정의
package org.xyz;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.ProceedingJoingPoint;
@Aspect
public class BeforeExample{
// dataAccessOperation이라는 미리 정의된 포인트컷 바로 전에 doAccesscheck 실행
@Before("com.xyz.myapp.CommonPointcuts.dataAccessOperation()")
public void doAccessCheck(){...}
}
@Aspect
public class AfterReturningExample{
// dataAccessOperation이라는 미리 정의된 포인트컷 리턴 후에 doAccesscheck 실행
@AfterReturning("com.xyz.myapp.CommonPointcuts.dataAccessOperation()")
public void doAccessCheck(){...}
}
@Aspect
public class AroundExample{
// dataAccessOperation이라는 미리 정의된 포인트컷 전과 후에 doAccesscheck 실행
@Around("com.xyz.myapp.CommonPointcuts.dataAccessOperation()")
public Object doBasicProfiling(ProceedingJoingPoint pjp) throws Throwable{
//start stopwatch
Object retVal = pjp.proceed();
//stop stopwatch
return retVal;
}
Validation
Validation?
- DATA 검증
문자열의 길이나 숫자형 데이터 값의 범위
email, 신용카드 번호 등 특정 형식에 맞춘 데이터
예) 배달앱인 경우 배달요청 시 해당 주문건이 결제완료 건인지 확인 등
경우에 따라 외부 API를 호출하거나 DB의 데이터 조회하여 검증할때도 있음.
Spring에서의 Validation
1. Java Bean Validation(추천..)
javaBean으로 간편하게 개별 데이터 검증
최근 가장 많이 활용되는 방법 중 하나이며, 아래 코드 처럼 javaBean내 Annotation으로 검증방법 명시
public class MemberCreationRequest{
@NotBlank(message="이름을 입력해주세요")
@Size(max=64 , message="이름의 최대 길이는 64자 입니다")
private String name;
@Min(0,"나이는 0보다 커야합니다.")
private int age;
@Email("이메일형식이 잘못되었습니다.")
private int email;
//Getter&Setter Area...//
}
@PostMapping(value="/member")
public MemberCreationResponse createMember(
@Valid @RequestBody final MemberCreationRequest memberCreationRequest){...}
)
위 처럼 dto에 어노테이션 명시 후 아래처럼 @Valid
어노테이션을 해당 @RequestBody
에 달게되면, Java Bean Validation을 수행 한 수 문제가 없을 때만 메서드 내부로 진입된다.
검증실패시에는 MethodargumentNotValidException
발생
2. Spring Validator Interface
support
: 이 Validator가 동작할 조건을 정의, 주로 class 타입비교
validate
: 원하는 검증을 진행
public class Person{
private String name;
private int age;
//getter & setter .... //
}
public class PersonValidator implements Validator{
public boolean supports(Class clazz){
return Person.class.equals(clazz);
}
public void validate(Object obj,Errors e){
ValidationUtils.rejectIfEmpty(e,"name","name.empty");
Person p = (Person) obj;
if(p.getAge()<0){
e.rejectValue("age","negativevalue");
}else if (p.getAge()>110){
e.rejectValue("age","too.old");
}
}
}
주의사항
- 가능한 validation은 로직 초기에 수행 후 실패시 exception 발생이 편리함
실무활용패턴(추천)
Data Binding
사용자나 외부 서버의 요청 데이터를 특정 도메인 객체에 저장해 프로그램 Request에 담아주는 것.
Converter<S,T>Interface
S(source)라는 타입을 받아 T(Target)이라는 타입으로 변환해주는 인터페이스
[Interface 모양]
package org.springframework.core.conver.converter;
public interface Converter<S,T>{
T convert(S source);
}
[사용 예시]
GET / user-info
x-auth-user : {"id":123,"name":"Paul"}
//유저 객체
public class XAuthUser{
private int id;
private String name;
...
//getter&setter Area
}
@GetMapping("/user-info")
public UserInfoResponse getUserInfo(
@RequestHeader("x-auth-user") XAuthUser xAuthUser){
...(logic)
}
)
@Component
public class XAuthUserConverter implements Converter<String,XAuthUser>{
@Override
public XAuthUser convert(String source){
return objectMapper.readValue(source,XAuthUser.class);
}
}
Formatter
특정객체<-> String 간의 변환 담당
[예시]
아래 메서드 설명
print
: API요청에 대한 응답을 줄 때, Date형식으로 된 데이터를 특정 locale에 맞춘 String으로 변환
parse
: API요청을 받아올 때, String으로 된 “2021-01-01 13:15:00”과 같은 날짜 형식의 데이터를 Date로 변환
package org.springframework.format.datetime;
@Component
public final class DateFormatter implements Formatter<Date>{
public String print(Date date, Locale locate){
return getDateFormat(locale).format(date);
}
public Date parse(String formatted, Locale locate) throws ParseException {
return getDateFormat(locale).parse(formatted);
}
//등등.....
}
SpEL
SpEL : Spring Expression Language
#{<expression string>}
방식으로 preperty 설정.
@Component
public class SimpleComponent{
@Value("#{ 1 + 1 }")
int two; // 2
@Value("#{ 2 eq 2 }")
boolean isTrue; // true
@Value("${ server.hostname }")
String hostName; // www.server.com
//등등 ....
}