데이터를 관리할 때, 비밀번호와 같은 중요한 데이터암호화할 필요가 있다. ( 나쁜 시스템 관리자가 있을 수 있으니..)

 

중요한 데이터를 복호화할 수 없는 알고리즘을 사용하여 암호화하여 관리해야한다. 

 

암호화 시 사용할 알고리즘은 SHA-256이다. SHA-256는 해시 함수중에 하나로서, 해시의 결과가 256bit이라고 한다.

 

 

Java에서 제공하는 MessageDigest 를 사용하여 암호화할 것이다.

 

순서로서는

  1. String 형태로 들어오는 암호화될 대상을 byte[]로 쪼갠 뒤, 
  2. MessageDigest 객체를 이용하여 해쉬함수를 통해 암호화된 결과를 byte[]형태로 반환받는다.
  3. 결과를 16진수 문자열로 변환시켜 String 형태로 변환하여 완성한다.

 

4. 이때, 1자리 수로 반환되는 경우가 있기 때문에 변환된 문자의 결과 길이가 1일 때마다 아무 문자나 앞이나 뒤에 추가해준다.

 

 

 

 

 

 

 

 

 

 

 

public String getSecureData(String password) {
		StringBuffer sb = new StringBuffer();//문자열을 누적시킬 객체
	
		try {
			//분해하여 16진수로 변환
			MessageDigest digest = MessageDigest.getInstance("SHA-256");
			byte[] data = password.getBytes("UTF-8"); //String형을 byte[]로 쪼갰다.
			byte[] hash = digest.digest(data);
			
			//쪼개진 데이터를 대상으로 16진수값으로 변환!!
			for(int i=0;i<hash.length;i++) {
				String hex = Integer.toHexString(0xff&hash[i]);//16진수 문자열로 변환
				if(hex.length()==1) {
					sb.append("0");
				}
				sb.append(hex);
			}
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		
		return sb.toString();
	}

같은 문자열을 암호화할 시 같은 암호화된 문자열이 반환되므로, 비밀번호와 같은 데이터를 암호화하여 사용할 수 있다.

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

java - mail 보내기  (0) 2021.01.06
싱글톤 패턴 알아보기  (0) 2020.12.14
JavaFX - 개발환경 구축 및 생명주기  (0) 2020.11.23
Java - JSON & XML 파싱  (0) 2020.11.17
Java - 소켓프로그래밍 기초 Echo System  (0) 2020.11.09

회원가입과 같이 mail을 보낼 경우 사용할 수 있다.

 

구글에서 제공하는 API를 사용해보겠다.

 

 

  • java에서 제공하는 dependency를 등록한다.
<!-- https://mvnrepository.com/artifact/javax.mail/mail -->
		<dependency>
			<groupId>javax.mail</groupId>
			<artifactId>mail</artifactId>
			<version>1.5.0-b01</version>
		</dependency>
  • 우선 구글로 접속하여 로그인한 뒤 google계정 탭으로 이동한다.

  • 보안 탭을 열어 2단계 인증 및 앱 비밀번호를 설정한다.

  • 앱 비밀번호를 이용하여 아래의 코드를 따라서 작성하고, 원하는 제목, 내용을 기입하여 보낼 수 있다!
import java.util.Properties;
import javax.mail.Authenticator;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;

public class MailService {
	String host = "smtp.gmail.com";
	String user = "나의계정@gmail.com";
	String password = "앱비밀번호";
	Properties props = new Properties();
	
	public void send() {
		props.put("mail.smtp.host", host);
		props.put("mail.smtp.port", 465);
		props.put("mail.smtp.auth", "true");
		props.put("mail.smtp.ssl.enable", "true");
		props.put("mail.smtp.ssl.trust", "smtp.gmail.com");

		Session session = Session.getDefaultInstance(props, new Authenticator() {
			protected PasswordAuthentication getPasswordAuthentication() {
	               return new PasswordAuthentication(user, password);
	            }	
		});
		
		try {
			
			MimeMessage message = new MimeMessage(session);
			message.setFrom(new InternetAddress(user));
			message.addRecipient(Message.RecipientType.TO, new InternetAddress("받는사람이메일"));
			message.setSubject("보낼제목");
			message.setContent("<h1>this is</h1> content", "text/html;charset=utf-8");
			
			Transport.send(message);
			System.out.println("Success Message Send");
		} catch (MessagingException e) {
			e.printStackTrace();
		}
	}
	public static void main(String[] args) {
		new MailService().send();
	}
}
[출처] Java Mail HTM형식으로 보내기|작성자 원리파고

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

java - 암호화  (0) 2021.01.06
싱글톤 패턴 알아보기  (0) 2020.12.14
JavaFX - 개발환경 구축 및 생명주기  (0) 2020.11.23
Java - JSON & XML 파싱  (0) 2020.11.17
Java - 소켓프로그래밍 기초 Echo System  (0) 2020.11.09

Spring에서 지원하는 ServletContextAware를 구현(implements)하면 거의 거져 먹여주는 꼴이다.

 

@Controller
public class TestController implements ServletContextAware{
	@Override
	public void setServletContext(ServletContext servletContext) {
		this.servletContext = servletContext;
	}
}

 

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

Spring | collection & association  (0) 2020.12.24
Spring | AOP  (0) 2020.12.23
Spring - DI  (0) 2020.12.22

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

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

 

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

 

비동기 통신을 하기 위해 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

DI(Dependency Injection)란?

직역하면 "의존성 주입"이라는 표현을 할 수 있지만, 이는 개념을 이해하기에 좋지 못한 표현이다. Spring에서 사용하는 뜻에 맞게 의역하면 "의존성있는 객체는 외부에서 주입하는 것"이라고 표현할 수 있다.

 

public class FryPan{
	public void boil(){
    	System.out.println("불을 이용해 요리합니다.");
    }
}
public class Cook{
	FryPan fryPan;
    public void init(){
    	fryPan = new FryPane();
    }
    
    public static void main(String[]agrs){
    	fryPan.boid();
    }
}

예를 들어 위와 같은 코드보면, Cook클래스은 FryPan클래스의 의존하고 있는 상태이다. 

위와 같이 의존성이 강한 상태에서 fryPan의 인스턴스를 생성하기 위해서 new연산자를 이용할 수 밖에 없다.

이는 FryPan을 다른 클래스로 바꿔야한다는 상황이 올 때 직접 Cook코드를 열어 바꿔줘야한다.

-> 코드가 길어지고 복잡해지면 유지보수가 까다롭다.

public inteface Pan{
	public void boil();
}
public class FryPan implements Pan{
	@Override
    public void boil(){
    	System.out.println("불로 요리를 합니다");
    }
}
public class Cook{
	Pan pan;
	
    public void setPan(Pan pan){
    	this.pan = pan;
    }
    
    public static void main(String[]agrs){
    	fryPan.boid();
    }
}

위와 같이 인터페이스를 이용하여 코드의 결합도를 낮춰주고 좀더 유연하게 할 수 있다.

 

그리고 여기서 Spring은 xml을 이용해서 인스턴스를 생성해줄 수 있다!!

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

	<!-- 앞으로, 소스코드에서 new하지말고, 이 xml설정파일에서 사용할 객체를 명시하면 된다... 
		, 스프링의 ApplicationContext가 알아서 메모리에 인스턴스를 생성하고, 주입까지 해준다!!
		단, 주입받으려는 객체는 setter나 생성자가 명시되어 있어야  스프링이 주입을 할 수 있다.-->
	
	<!-- 프라이팬을 선언 -->
	<!-- 하나의 컴포넌트 = bean -->
	<bean id="friPan" class="food.FriPan"/>	
	<bean id="cook" class="food.Cook">
		<!-- cook내의 pan을 주입  
			cook내의 setter메서드 호출-->
		<property name="pan" ref="friPan"/>
	</bean>
</beans>
package food;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class UseCook {
	public static void main(String[] args) {

		/*DI (Dependency Injection) 
		 : 직역 시, 의존성 주입..
		의역 시, 의존성있는 객체는 외부에서 주입받자!!!!
		 */		
			
		//스프링을 이용하지 않고 구현한 예
		//팬을 올리자
		/*
		 * FriPan pan = new FriPan(); Cook cook = new Cook();
		 * 
		 * cook.setPan(pan);//팬을 요리사에게 주입시키자!!
		 * 
		 * cook.makeFood();
		 */
		
		//스프링을 이용해서 객체를 주입시켜본다..
		//xml에 원하는 객체를 명시하면, 이 객체가 작성된 xml을 파악하여
		//객체들의 인스턴스를 생성관리해준다.. 이러한 역할을 수행하는 객체를 가리켜
		//Spring Context 객체라 한다!!!!! (외부파일을 통해 인스턴스 관리)
		ClassPathXmlApplicationContext context = null; //스프링xml 설정파일을 읽어서 작성된
		//객체의 인스터는스를 생성 및 관리해준다(주입도 해줌)
		//외부조립자(Assembler)
		context = new ClassPathXmlApplicationContext("spring/config/context.xml");
		
		//xml이 이미 읽혀진 상태이므로, 메모리에는 인스턴스들이 존재할 것이고, 그 중 어떤 인스턴스를 가져올지는
		//getBean메서드로 가져오면 된다..
		Cook cook = (Cook)context.getBean("cook");
		cook.makeFood();
	}
}

 

ClassPathXmlApplication객체를 이용하여 인스턴스를 생성할 xml을 지정하여 사용할 수 있다.

 

스프링을 사용하면 외부파일인 XML로 코드를 유지보수할 수 있고 코드의 결합도를 낮출 수 있다!

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

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

MVC패턴이란?

  • 구현된 개발코드를 의미하는게 아니라, 어플리케이션 개발 시 디자인과 로직은 분리시켜 개발해야 추후 변경사항이 발생했을 때 많은 리소스(개발시간, 인력)를 소모하지 않고 유지보수할 수 있다는 IT의 전해 내려오는 개발방법이론(개발패턴)
  • 자바로 구현한 MVC패턴을 모델2방식이라 한다.
  • ms개발자, .net개발자도 사용 즉, 어떠한 개발에도 사용되는 방식

 

Model

  • 중립적 로직이라서 스윙, 웹 모두 사용할 수 있는 중립적 코드  일반클래스로 정의하면 된다.
  • DAO, DTO와 같은 클래스들이라고 말할 수 있다.

View

  • 디자인적인 요소를 담당하는 부분이다.
  • JSP와 같이 태그들이 들어가는 코드라고 말할 수 있다.

Controller

  •  로직인 Model과 디자인인 View를 분리시키기 위한 용도
  • 웹이건, 응용프로그램이건 모든 컨트롤러 5대역할 

                     1. 요청을 받는다. 
                     2. 요청을 분석한다.. 
                     3. 알맞는 로직 객체에게 일을 시킨다.(지가 직접안함) 
                     4. 일 시킨 후(3단계) 결과가 있다면 결과를 보관한다. 
                     5. 디자인에 그 결과를 반영한다.

  • Servlet과 같은 클래스이다.

 

게시판목록페이지의 코드로 예를 들어보자

 

아래의 코드는 게시판목록의 View담당하는 JSP코드이다. 

DAO와 같은 클래스를 가지고 있지 않다.

<%@page import="com.webapp1216.board.model.Notice"%>
<%@page import="com.webapp1216.common.board.Pager"%>
<%@page import="java.util.List"%>
<%@ page contentType="text/html;charset=utf-8"%>
<%
	List<Notice> list = (List<Notice>)session.getAttribute("noticeList");
	Pager pager = new Pager();
	pager.init(request, list); // 페이지 처리에 대한 계산!!
%>
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
table {
	border-collapse: collapse;
	border-spacing: 0;
	width: 100%;
	border: 1px solid #ddd;
}

th, td {
	text-align: left;
	padding: 16px;
}

tr:nth-child(even) {
	background-color: #f2f2f2;
}

img{
	width:100px;
}
</style>
</head>
<body>

	<table>
		<tr>
			<th>No</th>
			<th>제목</th>
			<th>작성자</th>
			<th>작성일</th>
			<th>조회수</th>
		</tr>
		<%int num = pager.getNum(); %>
		<%int cusPos = pager.getCurPos(); %>
		<%for(int i=0;i<pager.getPageSize();i++){ %>
			<%if(num<1)break; %>
				<%Notice notice= list.get(cusPos++); %>
				<tr>
					<td><%=num-- %></td>
					<td><a href="/board/detail?notice_id=<%=notice.getNotice_id()%>"><%=notice.getTitle() %></a></td>
					<td><%=notice.getWriter() %></td>
					<td><%=notice.getRegdate() %></td>
					<td><%=notice.getHit() %></td>
				</tr>
		<%} %>
		  <tr>
			<td colspan="6" style="text-align: center">
			<%if(pager.getFirstPage()-1<=0){ %>
				<a href="javascript:alert('처음페이지입니다.')">◀</a>
			<%}else{ %>
			<a href="list.jsp?currentPage=<%=pager.getFirstPage()-1%>">◀</a>
			<%} %>
				<%for(int i=pager.getFirstPage();i<=pager.getLastPage();i++) {%>
					<%if(i<=pager.getTotalPage()){ %>
						<a href="list.jsp?currentPage=<%=i%>">[<%=i %>]</a>
					<%} %>
				<%} %>
				<%if(pager.getLastPage()>=pager.getTotalPage()){ %>
				<a href="javascript:alert('마지막페이지입니다.')">▶</a>
			<%}else{ %>
				<a href="list.jsp?currentPage=<%=pager.getLastPage()+1%>">▶</a>
			<%} %>
			</td>
		</tr>
		 -<tr>
			<td colspan="6">
				<button type="button" onClick="location.href='regist_form.jsp'">글등록</button>
			</td>
		</tr>
	</table>

</body>
</html>

 

아래의 코드는 M와 V를 연결해주는 역할의 Controller이다.

어떠한 디자인적인 요소가 들어가지 않았다.

/*
 * javaEE 개발패턴 중 mvc패턴을 적용한 개발방법을 가리켜 model2방식이라 일컫는다.
 * 특히 jsp가 디자인에 사용되고 있으며, 웹 상의 요청을 받고 응답이 가능한 서블릿이 컨트롤러로서 역할을 수행하게 된다.
*/
package com.webapp1216.board.controller;

import java.io.IOException;
import java.util.List;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import com.webapp1216.board.model.Notice;
import com.webapp1216.board.model.NoticeDAO;

//클라이언트의 목록요청을 처리하는 서블릿 정의!!
public class ListServlet extends HttpServlet{
	NoticeDAO dao = new NoticeDAO();
	
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		List<Notice> list = dao.selectAll();
		//어떻게 list.jsp까지 살려서 보낼까???
		//세션? 클라이언트가 브라우저 프로세스를 닫지 않거나, 일정 시간내에 재접속했을 때 서버측의 메모리에
		//담겨진 정보를 사용할 수 있는 기술...(새로운 접속인 경우 세션 객체를 새로 생성되고, 세션아이디가 새롭게 발급됨..)
		//session을 어케 가져오지?
		//jsp에서의 session내장객체는 자료형이 HttpSession이다!!
		HttpSession session = request.getSession();//이 요청과 관련한 세션을 얻는다!
		session.setAttribute("noticeList", list);//세션 객체에 보관!
		
		
		//결과페이지 선택
		response.sendRedirect("/board/list.jsp");
	}
}

 

아래의 코드는 DAO를 담당하는 모델의 코드이다.

DB와의 연결을 통해 요청에 대한 응답하기위한 데이터를 처리하는 부분이다.

package com.webapp1216.board.model;

import java.util.ArrayList;
import java.util.List;

import org.apache.ibatis.session.SqlSession;

import com.webapp1216.mybatis.config.MybatisConfigManager;

public class NoticeDAO {
	MybatisConfigManager manager = MybatisConfigManager.getInstance();
	
	// CRUD

	public List<Notice> selectAll() {
		List<Notice> list =null;
		SqlSession sqlSession = manager.getSqlSession();
		list = sqlSession.selectList("Notice.selectAll");
		manager.close(sqlSession);
		return list;
	}
}

 

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

JSP | 서블릿(Servlet) 이해  (0) 2020.12.16
JSP | session  (0) 2020.12.16
JSP | 커넥션풀(Connection Pool)  (0) 2020.12.11
JSP | MyBatis 사용해보기  (0) 2020.12.10
JSP - 페이징 이해  (0) 2020.12.08

서블릿(Servlet)이란?

오직 웹서버에서만 해석 및 실행될 수 있는 JavaEE기반의 클래스이다.

 

서블릿의 생명주기

생명주기는 init(), service(), destory() 로 이해할 수 있다.

  • init() : 생성자 호출 후, 서블릿의 초기화 작업때문에 톰캣에 의해
    호출
  • service() : 동시에 많은 클라이언트의 요청을 처리하는 메서드이고, 
    동시에 호출되려면, 쓰레드에 의해 호출됨
  • destory() : 서블릿 소멸시점에 호출, 주로 서블릿이 보유하고 있는 자원들을
    반납하는 용도에 사용..

서블릿의 계보

자식                                        부모                                   할아버지

HttpServlet ( 웹용, 추상클래스) -> GenericServlet(추상클래스) -> Servlet(인터페이스)

 

쉽게 말하면 위와 같이 설명할 수 있다. 

Servlet인터페이스는 간단한 추상메서드들로만 구성되어있다.

GenericServlet은 Servlet보다 더 많은 메서드들로 구성되어있으며, Sun사에서 서블릿을 개발할 때 단순히 Http 즉 웹용으로만 개발하는 것이 아니라 더 방범위한 분야에서 사용할 수 있도록 GenericServlet과 같은 틀을 제공한다.

 

HttpServlet은 웹용의 서블릿을 개발할 때 사용되는 클래스이며, get, post.. 등 다양한 요청에 대해 대응할 수 있는 doGet, doPost.. doXXXX와 같은 메서드들을 지원해준다.

 

JSP는 서블릿이다.

JSP는 사실 서블릿이였다. 

JSP에는 지시영역, 선언부, 스크립틀릿, 표현식의 영역이 존재한다. 사실 서블릿의 영역들 중 한 부분인 것이였다.

<%@ page contentType="text/html;charset=utf-8"%>
<%!
	//멤버메서드, 멤버변수 .. 멤버란? 클래스에서 인스턴스가 갖는 변수, 메서드 작성하는 영역
	int x=5;
	public void test(){
	}
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Insert title here</title>
<style></style>
<script></script>
</head>
<body>
난 jsp야!!
</body>
</html>

위와 같은 JSP파일이 사실은 

/*
 * Generated by the Jasper component of Apache Tomcat
 * Version: Apache Tomcat/8.5.61
 * Generated at: 2020-12-15 02:23:06 UTC
 * Note: The last modified time of this file was set to
 *       the last modified time of the source file after
 *       generation to assist with modification tracking.
 */
package org.apache.jsp;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.jsp.*;

public final class test_jsp extends org.apache.jasper.runtime.HttpJspBase
    implements org.apache.jasper.runtime.JspSourceDependent,
                 org.apache.jasper.runtime.JspSourceImports {


	//멤버메서드, 멤버변수 .. 멤버란? 클래스에서 인스턴스가 갖는 변수, 메서드 작성하는 영역
	int x=5;
	public void test(){
	}

  private static final javax.servlet.jsp.JspFactory _jspxFactory =
          javax.servlet.jsp.JspFactory.getDefaultFactory();

  private static java.util.Map<java.lang.String,java.lang.Long> _jspx_dependants;

  private static final java.util.Set<java.lang.String> _jspx_imports_packages;

  private static final java.util.Set<java.lang.String> _jspx_imports_classes;

  static {
    _jspx_imports_packages = new java.util.HashSet<>();
    _jspx_imports_packages.add("javax.servlet");
    _jspx_imports_packages.add("javax.servlet.http");
    _jspx_imports_packages.add("javax.servlet.jsp");
    _jspx_imports_classes = null;
  }

  private volatile javax.el.ExpressionFactory _el_expressionfactory;
  private volatile org.apache.tomcat.InstanceManager _jsp_instancemanager;

  public java.util.Map<java.lang.String,java.lang.Long> getDependants() {
    return _jspx_dependants;
  }

  public java.util.Set<java.lang.String> getPackageImports() {
    return _jspx_imports_packages;
  }

  public java.util.Set<java.lang.String> getClassImports() {
    return _jspx_imports_classes;
  }

  public javax.el.ExpressionFactory _jsp_getExpressionFactory() {
    if (_el_expressionfactory == null) {
      synchronized (this) {
        if (_el_expressionfactory == null) {
          _el_expressionfactory = _jspxFactory.getJspApplicationContext(getServletConfig().getServletContext()).getExpressionFactory();
        }
      }
    }
    return _el_expressionfactory;
  }

  public org.apache.tomcat.InstanceManager _jsp_getInstanceManager() {
    if (_jsp_instancemanager == null) {
      synchronized (this) {
        if (_jsp_instancemanager == null) {
          _jsp_instancemanager = org.apache.jasper.runtime.InstanceManagerFactory.getInstanceManager(getServletConfig());
        }
      }
    }
    return _jsp_instancemanager;
  }

  public void _jspInit() {
  }

  public void _jspDestroy() {
  }

  public void _jspService(final javax.servlet.http.HttpServletRequest request, final javax.servlet.http.HttpServletResponse response)
      throws java.io.IOException, javax.servlet.ServletException {

    final java.lang.String _jspx_method = request.getMethod();
    if (!"GET".equals(_jspx_method) && !"POST".equals(_jspx_method) && !"HEAD".equals(_jspx_method) && !javax.servlet.DispatcherType.ERROR.equals(request.getDispatcherType())) {
      response.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, "JSP들은 오직 GET, POST 또는 HEAD 메소드만을 허용합니다. Jasper는 OPTIONS 메소드 또한 허용합니다.");
      return;
    }

    final javax.servlet.jsp.PageContext pageContext;
    javax.servlet.http.HttpSession session = null;
    final javax.servlet.ServletContext application;
    final javax.servlet.ServletConfig config;
    javax.servlet.jsp.JspWriter out = null;
    final java.lang.Object page = this;
    javax.servlet.jsp.JspWriter _jspx_out = null;
    javax.servlet.jsp.PageContext _jspx_page_context = null;


    try {
      response.setContentType("text/html;charset=utf-8");
      pageContext = _jspxFactory.getPageContext(this, request, response,
      			null, true, 8192, true);
      _jspx_page_context = pageContext;
      application = pageContext.getServletContext();
      config = pageContext.getServletConfig();
      session = pageContext.getSession();
      out = pageContext.getOut();
      _jspx_out = out;

      out.write('\r');
      out.write('\n');
      out.write("\r\n");
      out.write("<!DOCTYPE html>\r\n");
      out.write("<html>\r\n");
      out.write("<head>\r\n");
      out.write("<meta charset=\"utf-8\">\r\n");
      out.write("<title>Insert title here</title>\r\n");
      out.write("<style></style>\r\n");
      out.write("<script></script>\r\n");
      out.write("</head>\r\n");
      out.write("<body>\r\n");
      out.write("난 jsp야!!\r\n");
      out.write("</body>\r\n");
      out.write("</html>");
    } catch (java.lang.Throwable t) {
      if (!(t instanceof javax.servlet.jsp.SkipPageException)){
        out = _jspx_out;
        if (out != null && out.getBufferSize() != 0)
          try {
            if (response.isCommitted()) {
              out.flush();
            } else {
              out.clearBuffer();
            }
          } catch (java.io.IOException e) {}
        if (_jspx_page_context != null) _jspx_page_context.handlePageException(t);
        else throw new ServletException(t);
      }
    } finally {
      _jspxFactory.releasePageContext(_jspx_page_context);
    }
  }
}

서블릿 클래스로 웹컨테이너가 변환시켜 실행하는 것이다!!! 놀라지 않을 수가 없다!!

 

단지 JSP는 디자인적인 코드를 편히 하기위해 만들어낸 기술일 뿐이다!!!

 

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

JSP | MVC패턴에 대한 이해  (0) 2020.12.16
JSP | session  (0) 2020.12.16
JSP | 커넥션풀(Connection Pool)  (0) 2020.12.11
JSP | MyBatis 사용해보기  (0) 2020.12.10
JSP - 페이징 이해  (0) 2020.12.08

웹사이트의 로그인 성공 시 해당 사용자의 정보를 어떻게 가지고 있어야할까?

 

이는 세션쿠키를 이용해서 가지고 있을 수 있다!

 

즉 쉽게 말해서 클라이언트측에 남느냐 서버에 기록이 남느냐에 따라 쿠키(과자부스러기=흔적)이나 세션이냐

클라이언트에 흔적남기기 = 쿠키(Cookie)

서버에 흔적남기기 = 세션(Session)

 

우리는 Session에 대해 알아볼 것 이다.

 

정말 쉽게 말해보자면 클라이언트가 서버에 요청하면 해당 클라이언트에 이름표(?)를 붙여놓는다고 할 수 있다.

이제 그 이름표를 가지고 정보를 가지고 올 수 있다.

 

코드를 보면서 이해해보자!

아래의 예제는 클라이언트측의 코드(jsp)이다.

session.getAttribute(); 라는 코드가 의심스럽다.

파라미터로 값들을 구별할 수 있는 id값을 넣는 것이다. 서버측 코드를 보면 바로 이해할 수 있을 것이다.

<%@page import="admin.member.Admin"%>
<%@ page contentType="text/html;charset=utf-8"%>
<%
	//세션에서 데이터 꺼내기
	out.print("당신이 사용하고 있는 세션객체는 "+session);
	Admin admin = (Admin)session.getAttribute("ad");
	
	//만일 admin VO가 null이면? 인증을 거치지 않거나, 세션이 만료된 상황이므로, 현재
	//페이지에 대한 접근 자체를 막아야한다..
	if(admin!=null){
%>
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<%@ include file="/admin/inc/head.jsp" %>
<style>

</style>
</head>
<body>
<div><a href="#"><%=admin.getMid() %></a>님 반갑습니다.</div>
<a href="/admin/logout.jsp">로그아웃</a>
<%@include file="/admin/inc/topnavi.jsp" %>
<div style="padding-left:16px">
  <h2>Top Navigation Example</h2>
  <p>Some content..</p>
</div>

</body>
</html>
<%}else{%>
<script>
alert('올바르지 않은 접근입니다.');
history.back();
</script>
<%}%>

 

이제 서버측의 코드를 보자

단순히 서버에 저장된 id와 password랑 클라이언트측에서 파라미터로 보낸 id와 passsword가 같으면 세션에 저장을 한다.

session.setAttribute("세션ID", 저장할 객체(?)); 

<%@page import="admin.member.Admin"%>
<%@ page contentType="text/html;charset=utf-8"%>
<%@include file="/inc/lib.jsp" %>
<%
	/* 
	원래는 데이터베이스에서 조회를 해야하지만, 추후 하기로 하고
	일단은 스트링으로 비교해본다..
	*/
	String admin_id = "scott";
	String admin_pass="1234";
	
	String mid = request.getParameter("mid");
	String password = request.getParameter("password");
	
	if(admin_id.equals(mid)&&admin_pass.equals(password)){
		//로그인 성공에 대한 보상, 관리자 페이지 보여주기
		//js의 location.href와 동일한 기능의 jsp 기능 이용해보자
		Admin admin = new Admin();
		admin.setMid(mid);
		admin.setPassword(password);
		
		//jsp의 내장객체인 session객체는 클라이언트가 신규접속이라고 생각할 때, 새로운 session
		//인스턴스를 생성하고 세션 ID도 생성하여 세션에 부여한다..
		//이 세션은 클라이언트가 브라우저를 종료하지 않거나, 일정시간내에 재접속을 할 경우 계속
		//사용할 수 있다.. 따라서 웹은 stateless기반이지만, 서버측 메모리에 생성된 세션을 이용
		//하면 마치 연결이 유지된 것처럼 보여질 수 있다. 주용도) 로그인 후 회원정보를 모든 페이지에서
		//사용할 수 있는 기능, 장바구니 등에 사용..
		session.setAttribute("ad", admin);
		System.out.println("로그인 요청 시 사용중인 "+session);
		response.sendRedirect("/admin");//클라이언트로 하여금 지정한 url로 요청을 시도
	}else{
		out.print(getMsgBack("로그인 정보가 일치하지 않습니다"));
	}
%>

 

실행결과

 

위 코드를 이해한다면 DB와 연결하고 위와 비슷하게 세션을 저장하면 끝~

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

JSP | MVC패턴에 대한 이해  (0) 2020.12.16
JSP | 서블릿(Servlet) 이해  (0) 2020.12.16
JSP | 커넥션풀(Connection Pool)  (0) 2020.12.11
JSP | MyBatis 사용해보기  (0) 2020.12.10
JSP - 페이징 이해  (0) 2020.12.08

+ Recent posts