웹페이지에서 동기방식으로 서버로 데이터를 보낼 때, 클라이언트는 응답을 기다리고 다른 일을 처리할 수 없게 된다. 

이를 해결하기 위해서 비동기통신을 이용하게 된다. 

 

비동기통신을 이용하면 페이지를 새로 로드하지 않고 페이지를 재구성할 수 있다. 

 

비동기 통신을 하기 위해 ajax를 사용했다.

 

 

jQuery ajax() Method (w3schools.com)

 

위 사이트에서 jQuery에서 제공하는 ajax를 이용하는 법을 배울 수 있다.

$.ajax({
	url:"/admin/product/regist",
	type:"post",
        data:{
            id:"hi"
        },
	success:function(result){
		alert(result);
	}
});

 

위의 $.ajax형태를 보게 되면 JSON형식(key:value)으로 이루어져있다고 볼 수 있다.

url은 통신할 url 정보를 입력

type은 get/post... 와 같은 통신방식을 입력

data는 서버로 전송할 파라미터

success는 서버와 통신을 성공하고 서버로부터 결과값을 받았을 때 실행할 익명함수를 입력한다. 

 

 

비동기통신을 이용하여 파일업로드

var formData = new FormData($("form")[0]);//<form>태그와는 다름.. 전송할 때 파라미터들을 담을 수 있지만 이 자체가 폼태그가 아니다!!

//미리보기했던 이미지들은 파일컴포넌트화 되어있지 않기 때문에, 전송데이터에서 빠져있다..
//따라서 formData전송 전에, 동적으로 파일컴포넌트화시켜 formData에 추가하자!!!
//java에서의 improved for문과 동일한 역할(주로 컬렉션에서 객체를 꺼낼 때 사용..)
//formData.append(name값, 업로드할 파일 객체, 파일명);
$.each(uploadFiles, function(i, file){
//미리보기만 가능했던 이미지들을 전송할 수 있는 형태로 만듬
formData.append("addImg", file, file.name);//<input type="file" name="addImg"> 동일
console.log(file.name);
});

나는 이미지를 미리보기하여 태그에 추가하여서 form태그 안에 컴포넌트화되어 있지 않기 때문에 동적으로 파일컴포넌트화시켜서 비동기통신 시 데이터로 보냈다.

$.ajax({
    url:"/admin/product/regist",
    data:formData,
    contentType:false,/*false일 경우 multipart/form-data로 지정한 효과!*/
    processData:false,/*false일 경우 query-string으로 전송하지 않음, 문자열만 보내는게 아니라 이미지도 껴있기 떄문에 stream방식*/
    type:"post",
    success:function(result){
    alert(result);
    }
});

 

형식은 일반 문자열을 보낼 때와는 비슷하지만, 추가로 작성해야된 부분이 있다.

contentType를 false로 주게 되면, multipart/form-data형식으로 서버로 전송하겠다는 뜻이다.

procesData를 false로 주게 되면, test.com?id=dasd 이런 파라미터를 이용하여 데이터를 전송(query-string방식)하는 게 아니라, 이미지와 같은 데이터를 보내기위한 stream방식으로 보내기위함이다.

 

 

위의 emp는 dept의 deptno를 외래키로 참조하는 테이블이다.

내부조인 : select * from dept left outer emp e join on d.deptno = e.deptno;

외부조인 : select * from dept d left outer join emp e on d.deptno = e.deptno;

와 같이 SQL쿼리를 사용하여 조인할 수 있다. 

 

이렇게 값을 얻어서 VO에 넣어서 저장하기가 애매(?)할 수가 있다.

 

Mybatis를 이용하여 조인을 처리하여 VO의 저장할 수 있는 방법이 있다.

 

collection1:多관계에서 쓰이는 방법으로 부모의 레코드를 뽑아내면서 해당 레코드를 참조하는 자식의 레코드들을 뽑아낼 수 있다. -> 어떻게보면 이중포문과 비슷하다고 생각이 들 수 있다.

 

사용하게되는 태그 resultMap과 select면 된다.

resultMap은 select태그의 속성 중 resultMap이라는 속성이 존재한다.

resultMap을 먼저 선언한 뒤, select에서 참조하는 방법이다.

<!-- 조인 시 VO가 두개의 컬럼을 감당할 수 있어야함...  -->
	<!-- 쿼리결과와 객체간 매핑을 자동으로 하는 것이 아니라, 
	개발자가 주도하여 처리를 하고 싶을때는 별도의 매핑을 선언.. -->
	<!-- 매핑의 커스터마이징 -->
	<resultMap type="Dept" id="deptJoinEmp">
	<!-- column=query에서 뽑아진 컬럼명 -->
		<id column="deptno" property="deptno"/><!-- primary key -->
		<result column="dname" property="dname"/><!-- 일반컬럼 -->
		<result column="loc" property="loc"/>
		<!-- 부서정보가져오고 부서정보에 포함되는 외부에 있는 부서원정보가져오기-->
		<!-- Emp(ofType)로 구성된  List(javaType)-->
		<!-- deptno컬럼을 가져오겠다. -->
		<!-- propery는 set메서드를 생각 -->
		<collection column="deptno" javaType="java.util.List" ofType="Emp" select="Emp.select"  property="empList"/>
	</resultMap>
	<!-- 이중포문과 비슷 dept정보를 가져올 때 그 정보를 가지고 emp정보를 가져오고 다음 dept가져오면 그 dept에 대한 emp를 뽑아온다. -->
	<select id="selectAll" resultMap="deptJoinEmp">
		select deptno, dname, loc from dept 
	</select>
	

resultMap은 매핑을 개발자가 커스터마이징하여 내가 만든 VO에 맞게 조인할 수 있다.

resultMap태그의 속성 중 type은 만들 VO객체를 말하고 id는 select에서 참조할 수 있게 이름을 지어주는 것이다.

id는 테이블의 primary key를 매핑하는 것이고, result는 일반 컬럼들을 매핑하는 것이다.

위 태그의 속성 중 column은 쿼리로 뽑아배는 레코드의 컬럼을 말하고, property는 VO객체의 set메서드를 말한다.

collection의 속성 중 javaType은 만들 자료형을 말하고 ofType은 javaType이 List와 같은 제네릭형일 때 자료형을 정해준다. select는 자식의 Mapper에서의 사용할 쿼리id를 말한다.

 

<resultMap id="empJoinDept" type="Emp" >
		<id column="empno" property="empno"/><!-- primary key -->
		<result column="ename" property="ename"/>
		<result column="job" property="job"/>
		<result column="mgr" property="mgr"/>
		<result column="hiredate" property="hiredate"/>
		<result column="sal" property="sal"/>
		<result column="comm" property="comm"/>
		<!-- 자식관점에서는 부모와 1:1 관계로 가져옴 -->
		<association column="deptno" property="dept" javaType="Dept" select="Dept.selectById"/>
	</resultMap>
	
	<!-- 사원테이블 정보 가져오기 -->
	<select id="selectAll" resultMap="empJoinDept">
		select * from emp
	</select>

association1:1관계에서 사용할 수 있는 조인이다. 즉, 자식이 참조하고 있는 컬럼에 대한 부모레코드를 참조할 수 있다.

위 collection 이해할 수 있다면 association을 쉽게 이해할 수 있다.

'프로그래밍 > Spring' 카테고리의 다른 글

Spring - ServletContext 쉽게 가져오기  (0) 2021.01.05
Spring | AOP  (0) 2020.12.23
Spring - DI  (0) 2020.12.22

DI를 사용할 경우 클래스내의 멤버변수에 대한 의존도가 낮아지게 되면서 결합도가 낮아진다.

하지만, 멤버변수의 존재가 아예 사라진다는 경우에 과연 결합도가 없다고 할 수 있을까?

 

이를 해결하기위해 Spring에서는 AOP를 사용하였다.

 

AOP란?

클래스내의 멤버변수와의 의존도를 아예 없게 함으로써 다른 클래스와의 결합도를 낮추는 기법이다.

Spring은 AspectJ의 기술을 채용하여 사용하였다.  

 

쓰는 이유?

예로 쇼핑몰 웹사이트를 제작 시 장바구니, 구매 등등 로그인 상태를 체크를 반드시 필요로 하는 페이지가 존재한다.

이런 경우 AOP와 같은 기술을 사용하지 않게 되면 해당 페이지의 컨트롤러와 같은 클래스나 페이지내에서 의존하게 된다. 이를 AOP와 같은 기술을 사용하여 분리하게 되면 프로그램의 유지보수가 상당히 편할 것이다.

 

사용방법

mvnrepository의 Spring MVC를 가져와서 pom.xml에 추가해준다.

 

Spring에서 사용되는 jar들이 많이 생기는데 여기에서 AOP도 추가된다.

<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-webmvc</artifactId>
			<version>4.3.30.RELEASE</version>
		</dependency>

그리고 aspectJ에서 지원하는 weaber 또한 필요로 한다.

<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
		<dependency>
			<groupId>org.aspectj</groupId>
			<artifactId>aspectjweaver</artifactId>
			<version>1.8.14</version>
			<scope>runtime</scope>
		</dependency>

 

아래의 코드로 예를 들어본다면, Student클래스내에 각 메서드들의 실행 시작과 실행 후에 Bell클래스의 메서드인 startBell(), endBell()실행하도록 만들어봄으로써 AOP를 이해할 수 있다.

package test;

public class Student {
	
	public void study1() { //영어시간
//		System.out.println("♬ 시작 종"); //종이 울리는 것은 학생과 관련된 기능이 아님!!! 그리고 중복된다.
		System.out.println("1교시는 영어시간이에요");
	}
	public void study2() {//국어시간
		System.out.println("2교시는 영어시간이에요");	
	}
	public void study3() {//물리시간
		System.out.println("3교시는 물리시간이에요");	
	}
	public void study4() {//수학시간
		System.out.println("4교시는 수학시간이에요");
	}
}
package test;

public class Bell {
	public void startBell() {
		System.out.println("♬ 시작 종");
	}
	
	public void endBell() {
		System.out.println("♬ 종료 종");
	}
}

 

<!-- 학생과 벨을 엮어보자(weaving) -->
	
	<!-- AOP를 이용하기 위해서는, 공통로직 즉 횡단적 관심사항을 등록한다!! -->
	<bean id="bell" class="test.Bell"/>
	
	<!-- 어떤 시점에, 어떤 객체에게 횡단점 관심사항을 적용할지 xml태그로 서술한다..
		즉 프로그램 코드가 아닌 xml과 같은 설정파일에서 구현하는 방법을 선언적이라한다.. 
	-->
	<aop:config>
		<aop:aspect id="bellAspect" ref="bell">
			<!-- 어떤 시점에 벨이 관여할지를 결정 -->
			<!-- test..*(..) 테스트 패키지 아래의 모든 클래스의 모든 메서드 -->
			<aop:pointcut expression="execution(public * test.Student.*(..))" id="bellpointcut"/>
			<aop:pointcut expression="execution(public * test.Dog.*(..))" id="pointcutToDog"/>
			<!-- 공통기능 동작을 언제 할지, 즉 학생의 동작 이전에 적용, 이후에 동작시킬지.. -->
			<aop:before method="startBell" pointcut-ref="bellpointcut"/>
			<aop:after method="endBell" pointcut-ref="bellpointcut"/>
			<aop:before method="startBell" pointcut-ref="pointcutToDog"/>
			<aop:after method="endBell" pointcut-ref="pointcutToDog"/>
		</aop:aspect>
	</aop:config>
	<bean id="student" class="test.Student"/>
	<bean id="dog" class="test.Dog"/>

Bell클래스의 인스턴스가 Student의 메서드들의 실행을 관찰하고 있다고 생각하면 쉬운 것 같다.

'프로그래밍 > Spring' 카테고리의 다른 글

Spring - ServletContext 쉽게 가져오기  (0) 2021.01.05
Spring | collection & association  (0) 2020.12.24
Spring - DI  (0) 2020.12.22

+ Recent posts