스프링

 

JDBCTemplate 연습 2 

 

 1). MySQL DB 사용자, 데이터베이스, 테이블 생성

사용자

생성
create user 'spring5'@'localhost' identified by 'spring5'; 
권한
grant all privileges on spring5fs.* to 'spring5'@'localhost';

 

데이터베이스

create database spring5fs default character set utf8;

 

테이블

create table spring5fs.MEMBER (
    ID int auto_increment primary key,
    EMAIL varchar(255),
    PASSWORD varchar(100),
    NAME varchar(100),
    REGDATE datetime,
    unique key (EMAIL) 
) engine=InnoDB character set = utf8;

데이터 추가해서 테스트

insert into member(email, password, name, regdate)
value ('asd@asd.com', '1234', '김복자', now());

 

 

 2). DTO 생성

package spring;

import java.time.LocalDateTime;

public class Member {

	private Long id;
	private String email;
	private String password;
	private String name;
	private LocalDateTime registerDateTime;

	public Member(String email, String password, 
			String name, LocalDateTime regDateTime) {
		this.email = email;
		this.password = password;
		this.name = name;
		this.registerDateTime = regDateTime;
	}

	void setId(Long id) {
		this.id = id;
	}

	public Long getId() {
		return id;
	}

	public String getEmail() {
		return email;
	}

	public String getPassword() {
		return password;
	}

	public String getName() {
		return name;
	}

	public LocalDateTime getRegisterDateTime() {
		return registerDateTime;
	}

	public void changePassword(String oldPassword, String newPassword) {
		if (!password.equals(oldPassword))
			throw new WrongIdPasswordException();
		this.password = newPassword;
	}

}

 

 

 

 3). DataSource 설정 ( DAO 만들고 주입 ) 

package config;

import org.apache.tomcat.jdbc.pool.DataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import spring.MemberDao;

@Configuration
public class AppCtx {
	
	
	@Bean(destroyMethod = "close") // 빈이 소멸될 때 커넥션 풀을 닫도록 설정
	public DataSource dataSource() {
		
		DataSource ds = new DataSource();
		ds.setDriverClassName("com.mysql.jdbc.Driver");
		ds.setUrl("jdbc:mysql://localhost:3306/spring5fs?"
				+"useSSL=true&useUnicode=true&characterEncoding=utf8");
		ds.setUsername("spring5");
		ds.setPassword("spring5");
		ds.setInitialSize(2); // 초기 커넥션 개수 지정
		ds.setMaxActive(10); // 최대 커넥션 개수 지정
		
		return ds;
		
	}
	// DAO 만들고 주입 
	@Bean
	public MemberDao memberDao() {
		return new MemberDao(dataSource());
	}
}

 

 

 

 

 4). DAO 설정 

1. JdbcTemplate 필드 선언 

2. DAO 생성자 만든 후 매개변수 DataSource 인자로 받음

3. 생성자 내부에서 JdbcTemplate 객체를 생성

이렇게 구현된 생성자를 통해 MemberDao 객체가 생성될 때마다 JdbcTemplate이 초기화되고, 이후 MemberDao 클래스 내에서 jdbcTemplate를 사용하여 데이터베이스와 상호작용하는 메서드들을 작성할 수 있다.

package spring;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;

import javax.sql.DataSource;

import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;

public class MemberDao {
	private JdbcTemplate jdbcTemplate;
	
	public MemberDao(DataSource dataSource) {
		this.jdbcTemplate = new JdbcTemplate(dataSource);
	}
	
	public Member selectByEmail(String email) {
		String sql = "select * from MEMBER where EMAIL = ?";
		List<Member> result = jdbcTemplate.query(sql, new MemberRowMapper(), email);
		return result.isEmpty() ? null : result.get(0);
				
	}
	
	public List<Member> selectAll(){
		String sql = "select * from member";
//		List<Member> result = jdbcTemplate.query(sql, 
//				new MemberRowMapper());
		
		// 람다식
		List<Member> result = jdbcTemplate.query(sql, 
				(ResultSet rs, int rowNum)->{
					Member member = new Member(
							rs.getString("email"),
							rs.getString("password"),
							rs.getString("name"), 
							rs.getTimestamp("regdate").toLocalDateTime());
					member.setId(rs.getLong("id"));
					return member;
				});
		
		return result;
	}
	
	public int count1() {
		String sql = "select count(*) from member";
		List<Integer> result = jdbcTemplate.query(
				sql, 
				new RowMapper<Integer>() {

					@Override
					public Integer mapRow(ResultSet rs, int rowNum) throws SQLException {
						return rs.getInt(1);
						
					}
					
				});
		return result.get(0);
	}
	
	// 람다식
	public int count2() {
		String sql = "select count(*) from member";
		List<Integer> result = jdbcTemplate.query(sql, 
				(ResultSet rs, int rewNum)->{
					return rs.getInt(1);
				});
		return result.get(0);
	}
	
}

 

 

 5). 실행 테스트

package main;

import java.util.List;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import config.AppCtx;
import spring.Member;
import spring.MemberDao;

public class TestSelEmail {

	public static void main(String[] args) {
		AnnotationConfigApplicationContext ctx = 
				new AnnotationConfigApplicationContext(AppCtx.class);
		
		MemberDao memberDao = ctx.getBean("memberDao", MemberDao.class);
		
//		Member member = memberDao.selectByEmail("madvirus@madvirus.com");
//		System.out.println(member);
		
		List<Member> list = memberDao.selectAll();
		for(Member m1 : list) {
			System.out.println(m1);
		}
	
//		System.out.println("count1 = " + memberDao.count1() );
//		System.out.println("count2 = " + memberDao.count2() );
	}
	
}

 

 

 

오라클

 

중복되지 않는 값 UNIQUE ( NULL은 여러 개 존재 가능 ) 

 

제약 조건 지정하기 ( 테이블 생성할 때 )

create table table_unique(
    login_id VARCHAR2(20) UNIQUE,
    login_pwd VARCHAR2(20) NOT NULL,
    tel VARCHAR2(20)
);

 

테이블에 데이터 넣기

insert into table_unique(login_id, login_pwd, tel)
VALUES ('Test_ID_01', 'PWD01', '010-1234-5678')

 

LOGIN_ID 열에 중복되는 데이터 넣기 ( 무결성 제약조건 위배 )

insert into table_unique(login_id, login_pwd, tel)
VALUES ('Test_ID_01', 'PWD01', '010-1234-5678')

 

LOGIN_PWD 열에 중복되는 데이터 넣기 ( NOT NULL 조건만 지정되어 있어서 가능 )

insert into table_unique(login_id, login_pwd, tel)
VALUES ('Test_ID_02', 'PWD01', '010-1234-5678')

LOGIN_ID 열에 NULL값 입력 ( 유니크니까 NULL값 입력 가능 )

insert into table_unique(login_id, login_pwd, tel)
VALUES (NULL, 'PWD01', '010-1234-5678')

 

 

 

 

JDBC => JDBCTemplate 변경 실습

 

DataSource 설정

package config;

import org.apache.tomcat.jdbc.pool.DataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import guestbook.dao.MessageDao;

@Configuration
public class AppCtx {
	
	
	@Bean(destroyMethod = "close") // 빈이 소멸될 때 커넥션 풀을 닫도록 설정
	public DataSource dataSource() {
		
		DataSource ds = new DataSource();
		ds.setDriverClassName("com.mysql.jdbc.Driver");
		ds.setUrl("jdbc:mysql://localhost:3306/guestbook?"
				+"useSSL=true&useUnicode=true&characterEncoding=utf8");
		ds.setUsername("jspexam");
		ds.setPassword("jsppw");
		ds.setInitialSize(2); // 초기 커넥션 개수 지정
		ds.setMaxActive(10); // 최대 커넥션 개수 지정
		
		return ds;
		
	}
	
	@Bean
	public MessageDao messageDao() {
		return new MessageDao(dataSource());
	}
	
}

 

DTO 동일 

package guestbook.model;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;

@Getter
@Setter
@ToString
@AllArgsConstructor
@NoArgsConstructor
public class Message {

	private int id;
	private String guestName;
	private String password;
	private String message;
	
	
	
	// 생성자 추가 
	public Message(String guestName, String password, String message) {
		super();
		this.guestName = guestName;
		this.password = password;
		this.message = message;
	}



	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getGuestName() {
		return guestName;
	}

	public void setGuestName(String guestName) {
		this.guestName = guestName;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public String getMessage() {
		return message;
	}

	public void setMessage(String message) {
		this.message = message;
	}

	public boolean hasPassword() {
		return password != null && !password.isEmpty();
	}

	public boolean matchPassword(String pwd) {
		return password != null && password.equals(pwd);
	}
}

 

 

DAO ( 주석으로 된게 기존 JDBC )

package guestbook.dao;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;

import org.apache.tomcat.jdbc.pool.DataSource;
import org.springframework.jdbc.core.JdbcTemplate;

import guestbook.model.Message;

public class MessageDao {
	
	private JdbcTemplate jdbcTemplate;
	
	public MessageDao(DataSource dataSource) {
		this.jdbcTemplate = new JdbcTemplate(dataSource);
	}
	
	private Message makeMessageFromResultSet(ResultSet rs) throws SQLException {
		Message message = new Message();
		message.setId(rs.getInt("message_id"));
		message.setGuestName(rs.getString("guest_name"));
		message.setPassword(rs.getString("password"));
		message.setMessage(rs.getString("message"));
		return message;
	}
	
	
	public int insert(Message message) {
		String sql = "insert into guestbook_message " + 
			"(guest_name, password, message) values (?, ?, ?)";
		return jdbcTemplate.update(sql, 
				message.getGuestName(),
				message.getPassword(),
				message.getMessage()
				
				);
		
	}
	
//	public int insert(Connection conn, Message message) throws SQLException {
//		PreparedStatement pstmt = null;
//		try {
//			pstmt = conn.prepareStatement(
//					"insert into guestbook_message " + 
//					"(guest_name, password, message) values (?, ?, ?)");
//			pstmt.setString(1, message.getGuestName());
//			pstmt.setString(2, message.getPassword());
//			pstmt.setString(3, message.getMessage());
//			return pstmt.executeUpdate();
//		} finally {
//			JdbcUtil.close(pstmt);
//		}
//	}

	public Message select(int messageId) {
		String sql = "select * from guestbook_message where message_id = ?";
		return jdbcTemplate.queryForObject(sql, 
				(ResultSet rs, int rowNum) -> {
					return makeMessageFromResultSet(rs);
				} ,messageId);
		
	}
	
//	public Message select(Connection conn, int messageId) throws SQLException {
//		PreparedStatement pstmt = null;
//		ResultSet rs = null;
//		try {
//			pstmt = conn.prepareStatement(
//					"select * from guestbook_message where message_id = ?");
//			pstmt.setInt(1, messageId);
//			rs = pstmt.executeQuery();
//			if (rs.next()) {
//				return makeMessageFromResultSet(rs);
//			} else {
//				return null;
//			}
//		} finally {
//			JdbcUtil.close(rs);
//			JdbcUtil.close(pstmt);
//		}
//	}


	public int selectCount() {
		String sql = "select count(*) from guestbook_message";
		Integer count = jdbcTemplate.queryForObject(sql, Integer.class);
				return count;
	}
	
//	public int selectCount(Connection conn) throws SQLException {
//		Statement stmt = null;
//		ResultSet rs = null;
//		try {
//			stmt = conn.createStatement();
//			rs = stmt.executeQuery("select count(*) from guestbook_message");
//			rs.next();
//			return rs.getInt(1);
//		} finally {
//			JdbcUtil.close(rs);
//			JdbcUtil.close(stmt);
//		}
//	}

	public List<Message> selectList(int firstRow, int endRow){
		String sql = "select * from guestbook_message " + 
				"order by message_id desc limit ?, ?";
		
		List<Message> result = jdbcTemplate.query(sql, 
				(rs, rowNum) -> makeMessageFromResultSet(rs), 
				firstRow - 1,
				endRow - firstRow + 1);
		
		return result;
	}
	
//	public List<Message> selectList(Connection conn, int firstRow, int endRow) 
//			throws SQLException {
//		PreparedStatement pstmt = null;
//		ResultSet rs = null;
//		try {
//			pstmt = conn.prepareStatement(
//					"select * from guestbook_message " + 
//					"order by message_id desc limit ?, ?");
//			pstmt.setInt(1, firstRow - 1);
//			pstmt.setInt(2, endRow - firstRow + 1);
//			rs = pstmt.executeQuery();
//			if (rs.next()) {
//				List<Message> messageList = new ArrayList<Message>();
//				do {
//					messageList.add(makeMessageFromResultSet(rs));
//				} while (rs.next());
//				return messageList;
//			} else {
//				return Collections.emptyList();
//			}
//		} finally {
//			JdbcUtil.close(rs);
//			JdbcUtil.close(pstmt);
//		}
//	}

	public int delete1(int messageId) {
		String sql = "delete from guestbook_message where message_id = ?";
		return jdbcTemplate.update(sql, messageId);
	
	}
	
//	public int delete(Connection conn, int messageId) throws SQLException {
//		PreparedStatement pstmt = null;
//		try {
//			pstmt = conn.prepareStatement(
//					"delete from guestbook_message where message_id = ?");
//			pstmt.setInt(1, messageId);
//			return pstmt.executeUpdate();
//		} finally {
//			JdbcUtil.close(pstmt);
//		}
//	}

}

'프로젝트 기반 자바(JAVA) 응용 SW개발자 취업과정' 카테고리의 다른 글

2023-08-07 57일차  (0) 2023.08.07
2023-08-04 56일차  (0) 2023.08.04
2023-08-02 54일차  (0) 2023.08.02
2023-08-01 53일차  (0) 2023.08.01
2023-07-31 52일차  (0) 2023.07.31

스프링

 

DB 연동

1. JDBC 프로그래밍의 단점을 보완하는 스프링

    // 반복 되는 코드 1
    Member member;
    Connection conn = null;
    PreparedStatement pstmt = null;
    ResultSet rs = null;
    
    try {
    	conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/chap14?");
    }
    // 반복 되는 코드 2
    finally {
			if (rs != null)
				try {rs.close();}catch(SQLException e2) {}
			if (pstmt != null)
				try {pstmt.close();}catch(SQLException e3) {}
			if (conn != null)
				try {conn.close();}catch(SQLException e3) {}	
    
    }

 

위에 코드를 보면 데이터 처리와는 상관없는 코드지만 JDBC 프로그래밍을 할 때 구조적으로 반복 된다.

구조적인 반복을 줄이기 위한 방법은 템플릿 메서드 패턴과 전략 패턴을 함께 사용하는 것이다.

스프링은 바로 이 두 패턴을 엮은 JdbcTemplate 클래스를 제공한다.

 

스프링이 제공하는 또 다른 장점은 트랜잭션 관리가 쉽다. 트랜잭션을 적용하고 싶은 메서드에 @Transactional

애노테이션을 붙이기만 하면 된다. ( 커밋 롤백 )

 

 

 

2. JDBC Template, DB 커넥션풀 사용 예제

 

 1). pom.xml

spring-jdbc : JdbcTemplate 등 JDBC 연동에 필요한 기능을 제공 ( 트랜잭션 기능 spring-tx모듈 자동으로 포함 )

tomcat-jdbc : DB 커넥션풀 기능을 제공

mysql-connector-java : MySql 연결에 필요한 JDBC 드라이버 제공

<?xml version="1.0" encoding="UTF-8"?>

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.db</groupId>
  <artifactId>chap5-sp5</artifactId>
  <version>0.0.1-SNAPSHOT</version>

  <name>chap5-sp5</name>
  <!-- FIXME change it to the project's website -->
  <url>http://www.example.com</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.source>11</maven.compiler.source>
    <maven.compiler.target>11</maven.compiler.target>
  </properties>

<dependencies>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-context</artifactId>
			<version>5.0.2.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>org.springframework</groupId>
			<artifactId>spring-jdbc</artifactId>
			<version>5.0.2.RELEASE</version>
		</dependency>
		<dependency>
			<groupId>org.apache.tomcat</groupId>
			<artifactId>tomcat-jdbc</artifactId>
			<version>8.5.27</version>
		</dependency>
		<dependency>
			<groupId>mysql</groupId>
			<artifactId>mysql-connector-java</artifactId>
			<version>8.0.33</version>
		</dependency>

		<dependency>
			<groupId>org.slf4j</groupId>
			<artifactId>slf4j-api</artifactId>
			<version>1.7.25</version>
		</dependency>

		<dependency>
			<groupId>ch.qos.logback</groupId>
			<artifactId>logback-classic</artifactId>
			<version>1.2.3</version>
		</dependency>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
    </dependency>
    
    <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok-maven-plugin -->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok-maven-plugin</artifactId>
    <version>1.18.20.0</version>
    <scope>provided</scope>
</dependency>

    
	</dependencies>

  <build>
    <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
      <plugins>
        <!-- clean lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#clean_Lifecycle -->
        <plugin>
          <artifactId>maven-clean-plugin</artifactId>
          <version>3.1.0</version>
        </plugin>
        <!-- default lifecycle, jar packaging: see https://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packaging -->
        <plugin>
          <artifactId>maven-resources-plugin</artifactId>
          <version>3.0.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-compiler-plugin</artifactId>
          <version>3.8.0</version>
        </plugin>
        <plugin>
          <artifactId>maven-surefire-plugin</artifactId>
          <version>2.22.1</version>
        </plugin>
        <plugin>
          <artifactId>maven-jar-plugin</artifactId>
          <version>3.0.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-install-plugin</artifactId>
          <version>2.5.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-deploy-plugin</artifactId>
          <version>2.8.2</version>
        </plugin>
        <!-- site lifecycle, see https://maven.apache.org/ref/current/maven-core/lifecycles.html#site_Lifecycle -->
        <plugin>
          <artifactId>maven-site-plugin</artifactId>
          <version>3.7.1</version>
        </plugin>
        <plugin>
          <artifactId>maven-project-info-reports-plugin</artifactId>
          <version>3.0.0</version>
        </plugin>
      </plugins>
    </pluginManagement>
  </build>
</project>

 

 

 2). DB 테이블 생성

 

1. root 계정에서 계정 생성 

create user 'jspexam'@'localhost' identified by 'jsppw';

 

 

2. 생성한 jspexam 계정 접속 후  데이터베이스 생성

create database (데이터베이스 이름) chap14 character set utf8mb4;

 

3. 데이터 베이스 권한 설정

grant all privileges on chap14.* to 'jspexam'@'localhost';

create user 'jspexam'@'%' identified by 'jsppw';
grant all privileges on chap14.* to 'jspexam'@'%';

 

4. 테이블 생성

create table chap14 (
memberid varchar(10) not null primary key,
password varchar(10) not null,
name varchar(20) not null,
email varchar(80)
)

 

5. 테스트용 테이블 데이터 추가

INSERT INTO member(memberid, password, name, email)
   VALUES ('test2', '1234', '김길순','hisnd@email.com')

 

 3). DataSource 설정 ( 커넥션 풀 관리 )

스프링이 제공하는 DB 연동 기능은 DataSource를 사용해서 DB Connection을 구한다. 

DB 연동에 사용할 DataSource를 스프링 빈으로 등록하고 DB연동 기능을 구현한 빈 객체는 DataSource를 주입받아 사용한다.Tomcat JDBC 모듈에서 DataSource 클래스를 제공 

package config;

import org.apache.tomcat.jdbc.pool.DataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import spring.MemberDao;

@Configuration
public class DbConfig {
	
	@Bean(destroyMethod = "close") // 빈이 소멸될 때 커넥션 풀을 닫도록 설정
	public DataSource dataSource() {
		
		DataSource ds = new DataSource();
		ds.setDriverClassName("com.mysql.jdbc.Driver");
		ds.setUrl("jdbc:mysql://localhost:3306/chap14?"
				+"useSSL=true&useUnicode=true&characterEncoding=utf8");
		ds.setUsername("jspexam");
		ds.setPassword("jsppw");
		ds.setInitialSize(2); // 초기 커넥션 개수 지정
		ds.setMaxActive(10); // 최대 커넥션 개수 지정
		
		return ds;
		
	}
	
	@Bean
	public MemberDao memberDao() {
		return new MemberDao(dataSource());
	}
}

 

 3). DbQueryConfig ( DbQuery 빈을 설정하고 등록, DataSource 자동 주입 설정 ) 

package config;

import org.apache.tomcat.jdbc.pool.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class DbQueryConfig {
	
	@Autowired
	private DataSource dataSource;
	// 클래스의 객체가 생성될 때 스프링은 dataSource 빈을 찾아서 자동으로 주입
	
	@Bean
	public DbQuery dbQuery() {
		return new DbQuery(dataSource);
	}
}

 

 4). DbQuery ( DAO, 데이터베이스 쿼리를 수행 ) 

package config;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

import org.apache.tomcat.jdbc.pool.DataSource;

import spring.Member;

public class DbQuery {
	private DataSource dataSource;
	
	
	public DbQuery(DataSource dataSource) {
		this.dataSource = dataSource;
	}
	// list 전체 출력
	public List selectAll() {
		Connection conn = null;
		List<Member> list = new ArrayList<>();
		try {
			conn = dataSource.getConnection();
			Statement stmt = conn.createStatement();
			String sql = "select * from member";
			ResultSet rs = stmt.executeQuery(sql);
			while(rs.next()) {
				list.add(new Member(
						rs.getString("memberid"),
						rs.getString("password"),
						rs.getString("name"),
						rs.getString("email")
						));
			}
			return list;
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return list;
		
		
	}
	// Select문 갯수
	public int count() {
		Connection conn = null;
		
		try {
			conn = dataSource.getConnection(); // 풀에서 구함
			try(Statement stmt = conn.createStatement();
			ResultSet rs = stmt.executeQuery("select count(*) from MEMBER")){
				rs.next();
				return rs.getInt(1);
			}
			
		} catch (SQLException e) {
			throw new RuntimeException(e);
		}finally {
			if (conn != null)
				try {
					conn.close(); // 풀에 반환 
				}catch (SQLException e) {
					
				}
		}
		
		
		
	}
	
}

 

 

 5). 실행 

package main;



import java.util.List;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import config.DbConfig;
import config.DbQuery;
import config.DbQueryConfig;
import spring.Member;



public class Ex1 {

	public static void main(String[] args) {
		AnnotationConfigApplicationContext ctx =
				new AnnotationConfigApplicationContext
				(DbConfig.class, DbQueryConfig.class);
		
		DbQuery dbQuery = ctx.getBean("dbQuery",DbQuery.class);
		int c1 = dbQuery.count();
		System.out.println(c1);
		
		List<Member> list = dbQuery.selectAll();
		for(Member member : list) {
			System.out.println(member);
		}

	}

}

 

 

 

 

JdbcTemplate(템플릿)을 이용한 쿼리 실행

스프링을 사용하면 DataSource나 Connection, Statemement, ResultSet을 직접 사용하지 않고 JdbcTemplate을 

이용해서 편리하게 쿼리를 실행할 수 있다.

 1). DB정보 토대로 DTO 만들기 ( CRUD하기 위해서 ) lombok 사용 

package spring;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;

@Getter
@Setter
@ToString
@AllArgsConstructor
@NoArgsConstructor
public class Member {
	private String memberid;
	private String password;
	private String name;
	private String email;
	
	
	
}

 

 2). JdbcTemplate 생성하기 ( DAO에 생성, DAO 생성자에 DataSource를 주입받도록 구현 ) 

여기서 주의해야 할 점은 마이바티스랑 틀리게 추가, 업데이트, 삭제 시 동일하게 jdbcTemplate.update 사용

package spring;


import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;

import javax.sql.DataSource;

import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;

public class MemberDao {
	private JdbcTemplate jdbcTemplate;
	
	public MemberDao(DataSource dataSource) {
		this.jdbcTemplate = new JdbcTemplate(dataSource);
	}
	
	// select 갯수 구현 
	public int count() {
		Integer count = jdbcTemplate.queryForObject("select count(*) from member", Integer.class);
	return count;
	}
	
	// insert 구현
	public void insert(Member member) {
		String sql = "insert into member(memberid, password, name, email)"
				+ "values (?,?,?,?)";
		jdbcTemplate.update(sql,
				member.getMemberid(), member.getPassword(),
				member.getName(), member.getEmail()
				);
	}
	
	// 업데이트 구현
	public void update(Member member) {
	    String sql = "update member set password=?, name=?, email=? "
	            + "where memberid = ?";

	    jdbcTemplate.update(sql,
	            member.getPassword(),
	            member.getName(), member.getEmail(), member.getMemberid()
	    );
	    System.out.println("업데이트 완료");
	}
	
	// 삭제 구현 
	public void delete(String id) {
		String sql = "delete from member where memberid = ?";
		
		jdbcTemplate.update(sql, id);
		System.out.println("삭제완료");
	}
	
	// List 전체 목록 출력 구현
	public List<Member> selectAll(){
		List<Member> result = jdbcTemplate.query("select * from member",
				new RowMapper<Member>() {

					@Override
					public Member mapRow(ResultSet rs, int rowNum) throws SQLException {
						Member member = new Member(
													rs.getString("memberid"),
													rs.getString("email"),
													rs.getString("password"),
													rs.getString("name"));
						return member;
					}
			
		});
		return result;
	}
}

 

 

3). 실행

package main;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import config.DbConfig;
import config.DbQueryConfig;
import spring.Member;
import spring.MemberDao;

public class TestMemberDao {

	public static void main(String[] args) {
		AnnotationConfigApplicationContext ctx =
				new AnnotationConfigApplicationContext(DbConfig.class, DbQueryConfig.class);
		MemberDao memberDao = ctx.getBean("memberDao", MemberDao.class);
		System.out.println(memberDao.count());
		
		 // 삭제
		//memberDao.delete("test4");
		
		// 조회
//		List<Member> list = memberDao.selectAll();
//		for(Member member : list) {
//			System.out.println(member);
//		}
		
		 // 생성 
		//memberDao.insert(new Member("test4", "111", "구마적", "sed@scd.com"));
		
		// 업데이트
		Member member = new Member("test4", "222", "신마적","ewewe@dd.com");
		memberDao.update(member);
		
		
	}

}

 

'프로젝트 기반 자바(JAVA) 응용 SW개발자 취업과정' 카테고리의 다른 글

2023-08-04 56일차  (0) 2023.08.04
2023-08-03 55일차  (0) 2023.08.03
2023-08-01 53일차  (0) 2023.08.01
2023-07-31 52일차  (0) 2023.07.31
2023-07-28 51일차  (0) 2023.07.28

스프링

 

@Autowired 애노테이션의 필수 여부 

 

dateTimeFormatter 필드가 null이면 날짜형식을 %tF로 출력하고 이 필드가 null이아니면 dateTimeFormatter를 이용해서 날짜 형식을 맞춰  출력하도록 print()메서드 수정 

밑에 코드를 보면 세터 메서드에 @Autowired 애노테이션을 주지 않아야 정상작동됨 왜냐하면 스프링설정클래스에 

자동 주입 할 @Bean이 없기 때문에 익셉션 발생 

 

package spring;

import java.time.format.DateTimeFormatter;

public class MemberPrinter {
	private DateTimeFormatter dateTimeFormatter;
	
	public MemberPrinter() {
		dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy년 MM월 dd일");
	}
	
	public void print(Member member) {
		if (dateTimeFormatter == null) {
			System.out.printf(
					"회원 정보: 아이디=%d, 이메일=%s, 이름=%s, 등록일=%tF\n", 
					member.getId(), member.getEmail(),
					member.getName(), member.getRegisterDateTime());
		} else {
			System.out.printf(
					"회원 정보: 아이디=%d, 이메일=%s, 이름=%s, 등록일=%s\n", 
					member.getId(), member.getEmail(),
					member.getName(), 
					dateTimeFormatter.format(member.getRegisterDateTime()));
		}
	}
	
	@Autowired
	public void setDateFormatter(DateTimeFormatter dateTimeFormatter) {
		this.dateTimeFormatter = dateTimeFormatter;
	}
	
}

 

이렇게 자동 주입할 대상이 필수가 아닌 경우에는 3가지 방법이있다. ( 필수 여부 지정하는 방법 )

 

1.

@Autowired 애노테이션의 required 속성을 false로 지정

false로 지정하면 매칭되는 빈이 없어도 익셉션이 발생하지 않으며 자동 주입을 수행하지 않는다.

나중에 유지보수를 위해 해당처럼 사용해도 괜찮음

	@Autowired(required = false)
	public void setDateFormatter(DateTimeFormatter dateTimeFormatter) {
		this.dateTimeFormatter = dateTimeFormatter;
	}

 

 

2.

스프링 5버전부터는 위에 처럼 말고 의존 주입 대상에 자바 8의 Optional 사용해도 된다.

일치하는 빈이 존재하지 않으면 값이 없는 Optional을 인자로 전달하고 ( 익셉션 발생되지 않음 )

일치하는 빈이 존재하면 해당 빈을 값으로 갖는 Optional을 인자로 전달

	@Autowired
	public void setDateFormatter(Optional<DateTimeFormatter>formatterOpt) {
		this.dateTimeFormatter = dateTimeFormatter;
	}

 

3.

@Nullable 애노테이션 사용 ( 스프링이 제공하는 애노테이션 ) 

스프링 컨테이너는 세터 메서드를 호출할 때 자동 주입할 빈이 존재하면 해당 빈을 인자로 전달하고,

존재하지 않으면 인자로 null을 전달

	@Autowired
	public void setDateFormatter(@Nullable DateTimeFormatter dateTimeFormatter) {
		this.dateTimeFormatter = dateTimeFormatter;
	}

 

3가지 방식은 필드에도 그대로 적용 가능 

1.

public class MemberPrinter {
	@Autowired(required = false)
	private DateTimeFormatter dateTimeFormatter;
	
	public MemberPrinter() {
		dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy년 MM월 dd일");
	}

 

2.

public class MemberPrinter {
	@Autowired
	private Optional<DateTimeFormatter>formatterOpt;
	private DateTimeFormatter dateTimeFormatter;
	
	public MemberPrinter() {
		dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy년 MM월 dd일");
	}

 

3.

public class MemberPrinter {
	@Autowired
	@Nullable
	private DateTimeFormatter dateTimeFormatter;
	
	public MemberPrinter() {
		dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy년 MM월 dd일");
	}

 

 

 

 

 

생성자 초기화와 필수 여부 지정 방식 동작 이해

밑에 코드 @Autowired(required = false)

info 출력 시 기본 생성자에서 초기화한 dateTimeFormatter를 사용해서 회원가입 일자 출력

package spring;

import java.time.format.DateTimeFormatter;

import org.springframework.beans.factory.annotation.Autowired;

public class MemberPrinter {
	private DateTimeFormatter dateTimeFormatter;
	
	public MemberPrinter() {
		dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy년 MM월 dd일");
	}
	
	public void print(Member member) {
		if (dateTimeFormatter == null) {
			System.out.printf(
					"회원 정보: 아이디=%d, 이메일=%s, 이름=%s, 등록일=%tF\n", 
					member.getId(), member.getEmail(),
					member.getName(), member.getRegisterDateTime());
		} else {
			System.out.printf(
					"회원 정보: 아이디=%d, 이메일=%s, 이름=%s, 등록일=%s\n", 
					member.getId(), member.getEmail(),
					member.getName(), 
					dateTimeFormatter.format(member.getRegisterDateTime()));
		}
	}
	
	@Autowired(required = false)
	public void setDateFormatter(DateTimeFormatter dateTimeFormatter) {
		this.dateTimeFormatter = dateTimeFormatter;
	}
	
}

 

 

 

 

밑에 코드 @Nullable

info 출력 시 dateTimeFormatter가 null일 때 결과가 출력 

package spring;

import java.time.format.DateTimeFormatter;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.lang.Nullable;

public class MemberPrinter {
	private DateTimeFormatter dateTimeFormatter;
	
	public MemberPrinter() {
		dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy년 MM월 dd일");
	}
	
	public void print(Member member) {
		if (dateTimeFormatter == null) {
			System.out.printf(
					"회원 정보: 아이디=%d, 이메일=%s, 이름=%s, 등록일=%tF\n", 
					member.getId(), member.getEmail(),
					member.getName(), member.getRegisterDateTime());
		} else {
			System.out.printf(
					"회원 정보: 아이디=%d, 이메일=%s, 이름=%s, 등록일=%s\n", 
					member.getId(), member.getEmail(),
					member.getName(), 
					dateTimeFormatter.format(member.getRegisterDateTime()));
		}
	}
	
	@Autowired
	public void setDateFormatter(@Nullable DateTimeFormatter dateTimeFormatter) {
		this.dateTimeFormatter = dateTimeFormatter;
	}
	
}

일치하는 빈이 없으면 값 할당 자체를 하지 않는 @Autowired(required = false)와 달리 @Nullable 애노테이션을 사용하면 일치하는 빈이 없을 때 null 값을 할당한다. 기본 생성자에서 자동 주입 대상이 되는 필드를 초기화할 때는 이 점에 유의 

 

 

 

 

 

 

컴포넌트 스캔

컴포넌트 스캔은 스프링이 직접 클래스를 검색해서 빈으로 등록해주는 기능이다. 설정 클래스에 빈으로 등록하지 않아도 

원하는 클래스를 빈으로 등록할 수 있으므로 컴포넌트 스캔 기능을 사용하면 설정 코드가 크게 줄어든다.

 

1. @Component 애노테이션으로 스캔 대상 지정

스프링이 검색해서 빈으로 등록할 수 있으려면 클래스에 @Component 애노테이션을 붙어야 한다.

해당 클래스를 스캔 대상으로 표시 

 

MemberDao 클래스

@Component
public class MemberDao

 

ChangePasswordService 클래스 

@Component
public class ChangePasswordService {

MemberRegisterService 클래스 

@Component
public class MemberRegisterService {

 

MemberInfoPrinter 클래스 ( 속성값 = 빈의 이름 ) 

@Component("infoPrinter")
public class MemberInfoPrinter {

MemberListPrinter 클래스 ( 속성값 = 빈의 이름 )  

@Component("listPrinter")
public class MemberListPrinter {

 

@Component 애노테이션에 값을 주었는지에 따라 빈으로 등록할 때 사용할 이름이 결정 된다. 

애노테이션에 값을 주지 않게 되면 클래스 이름의 첫 글자를 소문자로 바꾼 이름을 빈 이름으로 사용한다.

 

 

2. @ComponentScan 애노테이션으로 스캔 설정

스프링 설정 클래스에 적용

 

@ComponentScan(basePackages = {"spring"}) // 속성 값 "spring"은 패키지 이름 

spring 패키지와 그 하위 패키지에 속한 클래스를 스캔 대상으로 설정 

package config;

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

import spring.MemberPrinter;
import spring.MemberSummaryPrinter;
import spring.VersionPrinter;

@Configuration
@ComponentScan(basePackages = {"spring"})
public class AppCtx {

	@Bean
	@Qualifier("printer")
	public MemberPrinter memberPrinter1() {
		return new MemberPrinter();
	}
	
	@Bean
	@Qualifier("summaryPrinter")
	public MemberSummaryPrinter memberPrinter2() {
		return new MemberSummaryPrinter();
	}
	
	@Bean
	public VersionPrinter versionPrinter() {
		VersionPrinter versionPrinter = new VersionPrinter();
		versionPrinter.setMajorVersion(5);
		versionPrinter.setMinorVersion(0);
		return versionPrinter;
	}
}

 

 

 

3. 예제 실행

main클래스에서 일부 수정할 코드가 있는데 빈으로 검색하는 코드를 지워야됨

밑에 코드 "changePwdSvc" 제거 

	private static void processChangeCommand(String[] arg) {
		if (arg.length != 4) {
			printHelp();
			return;
		}
		ChangePasswordService changePwdSvc =
				ctx.getBean("changePwdSvc", ChangePasswordService.class);
		try {
			changePwdSvc.changePassword(arg[1], arg[2], arg[3]);
			System.out.println("암호를 변경했습니다.\n");
		} catch (MemberNotFoundException e) {
			System.out.println("존재하지 않는 이메일입니다.\n");
		} catch (WrongIdPasswordException e) {
			System.out.println("이메일과 암호가 일치하지 않습니다.\n");
		}
	}

 

밑에 코드 처럼 제거

	private static void processChangeCommand(String[] arg) {
		if (arg.length != 4) {
			printHelp();
			return;
		}
		ChangePasswordService changePwdSvc =
				ctx.getBean(ChangePasswordService.class);
		try {
			changePwdSvc.changePassword(arg[1], arg[2], arg[3]);
			System.out.println("암호를 변경했습니다.\n");
		} catch (MemberNotFoundException e) {
			System.out.println("존재하지 않는 이메일입니다.\n");
		} catch (WrongIdPasswordException e) {
			System.out.println("이메일과 암호가 일치하지 않습니다.\n");
		}
	}

 

 

 

 

 

 

 

오라클

 

빈값을 허락하지 않는 NOT  NULL

Not NULL은 특정 열에 데이터의 중복 여부와는 상관없이 NULL의 저장을 허용하지 않는 제약 조건이다. 반드시 열에 값이 존재해야만 하는 경우에 지정한다.열의 제약 조건으로 NOT NULL 지정 시 UPDATE문을 사용해서 ID나 Pwd에 NULL로 수정 불가

 

테이블을 생성할 때 NOT NULL 설정하기 

create table table_notnull(
    login_id VARCHAR2(20) not null,
    login_pwd VARCHAR2(20) not null,
    tel VARCHAR2(20)
);

 

 

제약 조건 이름 직접 지정

제약조건은 이름을 따로 지정해 주지 않으면 오라클에서 자동으로 이름이 지정됨 

실무에서 오라클이 자동으로 지정해 주는 이름이 제약 조건이 많아진 후 찾기 어려워질 수 있으므로 실무에서는

이름 붙이는 규칙을 정하여 제약 조건 이름을 직접 지정하는 경우가 많다.

 

테이블을 생성할 때 제약 조건에 이름 지정하기 

밑에 처럼 이름 지정 해주면 테이블이름_컬럼명_notnull 나중에 제약 조건이 뭔지 찾기 쉬움 

create table table_notnull2(
    login_id VARCHAR2(20) CONSTRAINT tblnn2_lgnid_nn not null,
    login_pwd VARCHAR2(20) CONSTRAINT tblnn2_lgnpw_nn not null,
    tel VARCHAR2(20)
);

 

 

 

 

 

'프로젝트 기반 자바(JAVA) 응용 SW개발자 취업과정' 카테고리의 다른 글

2023-08-03 55일차  (0) 2023.08.03
2023-08-02 54일차  (0) 2023.08.02
2023-07-31 52일차  (0) 2023.07.31
2023-07-28 51일차  (0) 2023.07.28
2023-07-27 50일차  (0) 2023.07.27

스프링

 

@Autowired를 이용한 의존 자동 주입

자동 주입 기능을 사용하면 스프링이 알아서 의존 객체를 찾아서 주입한다. 

 

1. 필드에 @Autowired

package spring;

import org.springframework.beans.factory.annotation.Autowired;

public class ChangePasswordService {
	
	@Autowired  // 자동 주입 설정
	private MemberDao memberDao;

	public void changePassword(String email, String oldPwd, String newPwd) {
		Member member = memberDao.selectByEmail(email);
		if (member == null)
			throw new MemberNotFoundException();

		member.changePassword(oldPwd, newPwd);

		memberDao.update(member);
	}

	public void setMemberDao(MemberDao memberDao) {
		this.memberDao = memberDao;
	}

}

해당 클래스 필드에 @Autowired 애노테이션이 붙어 있으면 스프링이 해당 타입의 빈 객체를 찾아서
필드에 할당한다.
	@Bean
	public ChangePasswordService changePwdSvc() {
		
		ChangePasswordService pwdSvc = new ChangePasswordService();
//		pwdSvc.setMemberDao(memberDao()); // 의존 객체 명시 하지 않아도 스프링이 알아서 자동 주입
		return pwdSvc;
	}
    
    주석 처리 한 부분처럼 @Bean에 의존을 주입을 안해도 된다.

 

 

2. 메서드에 @Autowired

package spring;

import org.springframework.beans.factory.annotation.Autowired;

public class MemberInfoPrinter {
	
	private MemberDao memDao;
	private MemberPrinter printer;

	public void printMemberInfo(String email) {
		Member member = memDao.selectByEmail(email);
		if (member == null) {
			System.out.println("데이터 없음\n");
			return;
		}
		printer.print(member);
		System.out.println();
	}
	@Autowired
	public void setMemberDao(MemberDao memberDao) {
		this.memDao = memberDao;
	}
	@Autowired
	public void setPrinter(MemberPrinter printer) {
		this.printer = printer;
	}

}

빈 객체의 메서드에 @Autowired을 붙이면 스프링은 해당 메서드를 호출한다 
이 때 메서드 파라미터 타입에 해당하는 빈 객체를 찾아 인자로 주입한다.

 

	@Bean
	public MemberPrinter memberPrinter() {
		return new MemberPrinter();
	}
    
    	@Bean
	public MemberInfoPrinter infoPrinter() {
		MemberInfoPrinter infoPrinter = new MemberInfoPrinter();
		return infoPrinter;
	}

위에 이미지는 @Autowired 애노테이션을 적용했을 때 주입이 어떻게 연결되는 보여주는 이미지

ChangePasswordService의 memberDao 필드 타입은 MemberDao이므로 일치하는 타입을 가진 memberDao 빈이

주입된다.  비슷하게 MemberInfoPrinter의 setMemberDao()메서드의 memberDao 파라미터 타입이 MemberDao 이므로 setMemberDao() 메서드에 일치하는 타입을 가진 memberDao 빈이 주입 된다. 

 

 

3. MemberRegisterService 클래스에 필드에 @Autowired추가 인자 없는 기본 생성자 추가 

public class MemberRegisterService {
	
	@Autowired
	private MemberDao memberDao;
	
	public MemberRegisterService() { // 인자 없는 기본 생성자 추가
		
	}
	
	public MemberRegisterService(MemberDao memberDao) {
		this.memberDao = memberDao;
	}

 

3. MemberListPrinter 클래스에 메서드에 @Autowired추가 인자 없는 기본 생성자 추가 

package spring;

import java.util.Collection;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;

public class MemberListPrinter {

	private MemberDao memberDao;
	private MemberPrinter printer;
	
	public MemberListPrinter() {
		
	}
	
	
	public MemberListPrinter(MemberDao memberDao, MemberPrinter printer) {
		this.memberDao = memberDao;
		this.printer = printer;
	}

	public void printAll() {
		Collection<Member> members = memberDao.selectAll();
		members.forEach(m -> printer.print(m));
	}
	
	@Autowired
	public void setMemberDao(MemberDao memberDao) {
		this.memberDao = memberDao;
	}
	@Autowired
	public void setMemberPrinter(MemberPrinter printer) {
		this.printer = printer;
	}
}

 

기본 생성자 추가하는 이유는 AppCtx 클래스에서 기본 생성자를 이용해서 객체를 생성하기 위함

 

 

스프링 빈으로 생성할 모든 클래스에 @Autowired 애노테이션을 적용 / 설정 클래스 의존 주입 코드 제거 

package config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import spring.ChangePasswordService;
import spring.MemberDao;
import spring.MemberInfoPrinter;
import spring.MemberListPrinter;
import spring.MemberPrinter;
import spring.MemberRegisterService;
import spring.MemberSummaryPrinter;
import spring.VersionPrinter;

@Configuration
public class AppCtx {

	@Bean
	public MemberDao memberDao() {
		return new MemberDao();
	}
	
	@Bean
	public MemberRegisterService memberRegSvc() {
		return new MemberRegisterService();
	}
	
	@Bean
	public ChangePasswordService changePwdSvc() {
		
		return new ChangePasswordService();
	}
	
	@Bean
	
	public MemberPrinter memberPrinter1() {
		return new MemberPrinter();
	}
	
//	@Bean
//	public MemberPrinter memberPrinter2() {
//		return new MemberPrinter();
//	}
	
	@Bean
	
	public MemberSummaryPrinter memberPrinter2() {
		return new MemberSummaryPrinter();
	}
	
	@Bean
	public MemberListPrinter listPrinter() {
		return new MemberListPrinter();
	}
	
	@Bean
	public MemberInfoPrinter infoPrinter() {
		MemberInfoPrinter infoPrinter = new MemberInfoPrinter();
		return infoPrinter;
	}
	
	@Bean
	public VersionPrinter versionPrinter() {
		VersionPrinter versionPrinter = new VersionPrinter();
		versionPrinter.setMajorVersion(5);
		versionPrinter.setMinorVersion(0);
		return versionPrinter;
	}
}

 

 

 

@Qualifier 애노테이션을 이용한 의존 객체 선택

자동 주입 가능한 빈이 두 개 이상이면 자동 주입할 빈을 지정할 수 있는 방법이 해당 애노테이션

	@Bean
	@Qualifier("printer")
	public MemberPrinter memberPrinter1() {
		return new MemberPrinter();
	}
	
	@Bean
	public MemberPrinter memberPrinter2() {
		return new MemberPrinter();
	}

해당 빈의 한정 값으로 "printer" 지정

 

public class MemberListPrinter {

	private MemberDao memberDao;
	private MemberPrinter printer;
	
	public MemberListPrinter() {
		
	}
	
	
	public MemberListPrinter(MemberDao memberDao, MemberPrinter printer) {
		this.memberDao = memberDao;
		this.printer = printer;
	}

	public void printAll() {
		Collection<Member> members = memberDao.selectAll();
		members.forEach(m -> printer.print(m));
	}
	
	@Autowired
	public void setMemberDao(MemberDao memberDao) {
		this.memberDao = memberDao;
	}
	@Autowired
	@Qualifier("printer")
	public void setMemberPrinter(MemberPrinter printer) {
		this.printer = printer;
	}
}

위에 지정한 한정 값은 @Autowired 애노테이션에서 자동 주입할 빈을 한정할 때 사용한다. ( 주입 대상 지정 ) 

 

 

 

 

 

상위 / 하위 타입 관계와 자동 주입

package spring;

public class MemberSummaryPrinter extends MemberPrinter {

	@Override
	public void print(Member member) {
		System.out.printf(
				"회원 정보: 이메일=%s, 이름=%s\n", 
				member.getEmail(), member.getName());
	}

}

해당 클래스는 MemberPrinter 클래스를 상속한 클래스 이다. 

해당 클래스는 MemberPrinter에 상속되어 있기 때문에 memberprinter1과 memberprinter2 타입 빈중에서 어떤 빈을주입해야 할지 알 수 없기 때문에 에러가 발생 

	@Bean
	public MemberPrinter memberPrinter1() {
		return new MemberPrinter();
	}

	@Bean
	public MemberSummaryPrinter memberPrinter2() {
		return new MemberSummaryPrinter();
	}

 

자동 주입이 되므로 어떤 빈을 주입할지 결정해야 한다. 

 

	@Bean
	@Qualifier("printer")
	public MemberPrinter memberPrinter1() {
		return new MemberPrinter();
	}
    
    	@Bean
	@Qualifier("summaryPrinter")
	public MemberSummaryPrinter memberPrinter2() {
		return new MemberSummaryPrinter();
	}

 

public class MemberListPrinter {

	private MemberDao memberDao;
	private MemberPrinter printer;
	
	public MemberListPrinter() {
		
	}
	
	
	public MemberListPrinter(MemberDao memberDao, MemberPrinter printer) {
		this.memberDao = memberDao;
		this.printer = printer;
	}

	public void printAll() {
		Collection<Member> members = memberDao.selectAll();
		members.forEach(m -> printer.print(m));
	}
	
	@Autowired
	public void setMemberDao(MemberDao memberDao) {
		this.memberDao = memberDao;
	}
	@Autowired
	@Qualifier("summaryPrinter")
	public void setMemberPrinter(MemberPrinter printer) {
		this.printer = printer;
	}
}

MemberListPrinter 클래스에 자동 주입할 MemberPrinter 타입 빈은 두 가지 방법으로 처리 하도록 설정

둘 중 하나 @Qualifiter 애노테이션으로 주입 대상 선택 가능하다.

 

 

 

JSP ( Cookie ( 쿠키 ) ) 

기본 개념 코드 

 

쿠키 생성하기

response 기본 객체의 addCookie()메서드를 사용하여 쿠키 추가 웹 브라우저에 쿠키 정보를 추가로 전송

getName() 리턴 타입 String : 쿠키의 이름을 구한다.

getValue() 리턴 타입 String : 쿠키의 값을 구한다. 

setMaxAge(int expiry) 리턴 타입 void : 쿠키의 유효 시간을 초 단위로 지정 / 음수를 입력할 경우 웹 브라우저를 닫을 때 쿠키가 함께 삭제

<%@page import="java.net.URLEncoder"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%
Cookie cookie = new Cookie("name1", "abcd1");
response.addCookie(cookie);
cookie = new Cookie("name2", "abcd2");
response.addCookie(cookie);
%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<%= cookie.getName() %> = <%=cookie.getValue() %><br/>
<%= cookie.getName() %> = <%=cookie.getValue() %>
</body>
</html>

쿠키 값 읽어오기

쿠키를 생성하고 그 다음부터는 생성한 쿠키를 사용할 수있다. 웹 브라우저는 요청 헤더에 쿠키를

저장해서 보내며, JSP 다음의 코드를 사용해서 쿠키 값을 읽어올 수 있다. 

Cookie[] cookies = request.getCookies();

request.getCookies() 메서드는 Cookie 배여를 리턴하며, 읽어올 쿠키가 존재하지 않을 경우 null을 리턴

 

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<%
Cookie[] cookies = request.getCookies();

if (cookies != null && cookies.length > 0) {
	
	for (int i=0; i < cookies.length; i++) {
		out.println("<br/>");
		out.println(cookies[i].getName()+"=");
		out.println(cookies[i].getValue());
	}
}
%>
</body>
</html>

 

 

쿠키 값 변경 

값을 변경하려는 쿠키가 존재하지 않는다면 새롭게 쿠키를 생성하게 된다.

쿠키가 존재하는 확인 후 값을 변경하는게 좋다.

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<%
Cookie[] cookies = request.getCookies();
if (cookies != null && cookies.length > 0) {
	for (int i=0; i < cookies.length; i++) {
		if (cookies[i].getName().equals("name1")) {
			Cookie cookie1 = new Cookie("name1", "zxcv");
			response.addCookie(cookie1);
		}
	}
}
%>
</body>
</html>

 

쿠키 삭제하기

쿠키를 삭제하는 기능을 별도로 제공하지는 않지만, 유효 시간을 0으로 지정해준 후 응답 헤더에 추가하면 삭제하게 된다

 

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<%
Cookie[] cookies = request.getCookies();
if (cookies != null && cookies.length > 0) {
	for (int i=0; i < cookies.length; i++) {
		if (cookies[i].getName().equals("name1")) {
			Cookie cookie1 = new Cookie("name1", "");
			cookie1.setMaxAge(0);
			response.addCookie(cookie1);
		}
	}
}
%>
</body>
</html>

 

 


 

 

 

유틸 코드 사용해서 생성, 읽기

 

유틸

package util;


import java.io.IOException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.util.Map;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest; 

public class Cookies {
	
	private Map<String, Cookie> cookieMap = 
			new java.util.HashMap<String, Cookie>();
	
	public Cookies(HttpServletRequest request) {
		Cookie[] cookies = request.getCookies();
		if (cookies != null) {
			for (int i = 0 ; i < cookies.length ; i++) {
				cookieMap.put(cookies[i].getName(), cookies[i]);
			}
		}
	}

	public Cookie getCookie(String name) {
		return cookieMap.get(name);
	}
	
	public String getValue(String name) throws IOException {
		Cookie cookie = cookieMap.get(name);
		if (cookie == null) {
			return null;
		}
		return URLDecoder.decode(cookie.getValue(), "utf-8");
	}

	public boolean exists(String name) {
		return cookieMap.get(name) != null;
	}

	public static Cookie createCookie(String name, String value)
	throws IOException {
		return new Cookie(name, URLEncoder.encode(value, "utf-8"));
	}

	public static Cookie createCookie(String name, String value, String path, 
		int maxAge) throws IOException {
		Cookie cookie = new Cookie(name, URLEncoder.encode(value, "utf-8"));
		cookie.setPath(path);
		cookie.setMaxAge(maxAge);
		return cookie;
	}
	
	public static Cookie createCookie(String name, String value, String domain,
			String path, int maxAge) throws IOException {
		Cookie cookie = new Cookie(name, URLEncoder.encode(value, "utf-8"));
		cookie.setDomain(domain);
		cookie.setPath(path);
		cookie.setMaxAge(maxAge);
		return cookie;
	}

}

 

 

생성

<%@page import="util.Cookies"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%
response.addCookie(Cookies.createCookie("name", "가나다"));
response.addCookie(Cookies.createCookie("id", "abc", "/", 60 ));
%>
    
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>

</body>
</html>

 

읽기 ( view )

<%@page import="util.Cookies"%>
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%
Cookies cookies = new Cookies(request);
%>    
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<% if (cookies.exists("id")){ %>
<%=cookies.getValue("id")%><br/>
<%} %>

<% if (cookies.exists("name")){ %>
<%=cookies.getValue("name")%><br/>
<%} %>
</body>
</html>

 

Cookie 로그인 예제 

 

loginForm.jsp

<%@ page contentType = "text/html; charset=utf-8" %>
<html>
<head><title>로그인폼</title></head>
<body>

<form action="<%= request.getContextPath() %>/member/login.jsp"
      method="post">
아이디 <input type="text" name="id" size="10">
암호 <input type="password" name="password" size="10">
<input type="submit" value="로그인">
</form>

</body>
</html>

login.jsp

로그인 아이디, 비밀번호 똑같은지 체크

<%@ page contentType = "text/html; charset=utf-8" %>
<%@ page import = "util.Cookies" %>
<%
	String id = request.getParameter("id");
	String password = request.getParameter("password");
	
	if (id.equals(password)) {
		// ID와 암호가 같으면 로그인에 성공한 것으로 판단.
		response.addCookie(
			Cookies.createCookie("AUTH", id, "/", -1)
		);
%>
<html>
<head><title>로그인성공</title></head>
<body>

로그인에 성공했습니다.

</body>
</html>
<%
	} else { // 로그인 실패시
%>
<script>
alert("로그인에 실패하였습니다.");
history.go(-1);
</script>
<%
	}
%>

loginCheck.jsp

로그인 상태 인지 확인

<%@ page contentType = "text/html; charset=utf-8" %>
<%@ page import = "util.Cookies" %>
<%
	Cookies cookies = new Cookies(request);
%>
<html>
<head><title>로그인여부 검사</title></head>
<body>

<%
	if (cookies.exists("AUTH")) {
%>
아이디 "<%= cookies.getValue("AUTH") %>"로 로그인 한 상태
<%
	} else {
%>
로그인하지 않은 상태
<%
	}
%>
</body>
</html>

logout.jsp

로그아웃 jsp 실행 시 쿠키 삭제되서 로그아웃 처리 됨 

 

'프로젝트 기반 자바(JAVA) 응용 SW개발자 취업과정' 카테고리의 다른 글

2023-08-02 54일차  (0) 2023.08.02
2023-08-01 53일차  (0) 2023.08.01
2023-07-28 51일차  (0) 2023.07.28
2023-07-27 50일차  (0) 2023.07.27
2023-07-26 49일차  (0) 2023.07.26

서블릿 MVC 패턴 모델 2

 

해당 코드 이용해서 List, View, write 핸들러 생성해서 실습 하기 

package command;

import java.io.FileReader;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;

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

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import config.AppCtx;

public class ControllerUsingURI extends HttpServlet {
	
	// 어디서든 사용할 수 있게 설정
	//public static ApplicationContext ctx;
	
	// @Autowired
	// BoardService boardService;
	ApplicationContext ctx;
	
    // <커맨드, 핸들러인스턴스> 매핑 정보 저장
    private Map<String, String> commandHandlerMap = 
    		new HashMap<>();
    // 서블릿 초기화 메서드
    public void init() throws ServletException {
    	
    	ctx = new AnnotationConfigApplicationContext(AppCtx.class);
    	
     	// configFile 초기화 파라미터를 읽어온다.
        // 이 값을 이용해서 설정 파일 경로를 구한다.
        String configFile = getInitParameter("configFile");
        System.out.println(configFile);
        Properties prop = new Properties();
        String configFilePath = getServletContext().getRealPath(configFile);
        System.out.println(configFilePath);
        // 설정 파일로부터 매핑 정보를 읽어와 Properties 객체에 저장한다.
        // Properties는 (이름, 값) 목록을 갖는 클래스로서,
        // 이 경우에는 프로퍼티 이름을 커맨드 이름으로 사용하고
        // 값을 클래스 이름으로 사용한다.
        try (FileReader fis = new FileReader(configFilePath)) { // 파일 읽기
        	// 설정 파일을 읽어서 Properties 객체에 로드 ( 맵에 보관 ) 
            prop.load(fis);
        } catch (IOException e) {
            throw new ServletException(e);
        }
        // Properties에 저장된 각 프로퍼티의 키에 대해 다음 작업을 반복한다.
        Iterator keyIter = prop.keySet().iterator();
        while (keyIter.hasNext()) {
        	// 1. 프로퍼티 이름을 커맨드 이름으로 사용한다.
            String command = (String) keyIter.next();
            // 2. 커맨드 이름에 해당하는 핸들러 클래스 이름을 Properties에서 구한다.
            String handlerClassName = prop.getProperty(command);
            commandHandlerMap.put(command, handlerClassName);
//            try {
//            	// 3. 핸들러 클래스 이름을 이용해서 Class 객체를 구한다.
//                Class<?> handlerClass = Class.forName(handlerClassName);
//                // 4. Class로부터 핸들러 객체를 생성한다. 
//                CommandHandler handlerInstance = 
//                        (CommandHandler) handlerClass.newInstance();
//             // 5. commandHandlerMap에 (커맨드, 핸들러 객체)에 대한 매핑 정보를 저장한다.
//                commandHandlerMap.put(command, handlerInstance);
//            } catch (ClassNotFoundException | InstantiationException 
//            		| IllegalAccessException e) {
//                throw new ServletException(e);
//            }
        }
    }

    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        process(request, response);
    }

    protected void doPost(HttpServletRequest request,
    HttpServletResponse response) throws ServletException, IOException {
        process(request, response);
    }
    
    // 클라이언트로부터 들어오는 HTTP 요청에 대해 처리를 수행
    // 그에 맞는 핸들러를 호출하여 요청을 처리하고 결과를 뷰 페이지에 전달
    private void process(HttpServletRequest request,
    HttpServletResponse response) throws ServletException, IOException {
    	// 클라이언트가 요청한 URI를 가져온다.
		String command = request.getRequestURI();
		// 요청된 URI가 웹 어플리케이션의 Context Path(컨텍스트 경로)로 시작한다면,
		// Context Path 부분을 제거하여 실제로 처리할 명령어를 추출
		// 예)/hello.do 추출
		if (command.indexOf(request.getContextPath()) == 0) {
			command = command.substring(request.getContextPath().length());
		}
		System.out.println(command);
		// 추출된 명령어를 사용하여 commandHandlerMap에서 해당 커맨드에 대응하는 핸들러를 가져온다.
		// commandHandlerMap은 init() 메서드에서 설정 파일로부터 읽어온 커맨드와 핸들러 클래스를 매핑한 맵
//        CommandHandler handler = commandHandlerMap.get(command);
//        // 만약 해당 명령어에 대응하는 핸들러가 없다면, 기본적으로 NullHandler를 사용
//        if (handler == null) {
//            handler = new NullHandler();
//        }
        // 찾아낸 핸들러를 사용하여 실제 요청 처리를 수행
        // 핸들러의 process() 메서드를 호출하여 요청 처리 결과로 뷰 페이지의 경로를 가져온다.
        // 최종적으로 클라이언트에게 보여질 JSP 페이지의 위치를 나타낸다.
        String handler = commandHandlerMap.get(command);
        System.out.println(handler);
        // 인터페이스 다형성
        CommandHandler helloHandler = ctx.getBean(handler, CommandHandler.class);
		String viewPage = null;
        try {
            viewPage = helloHandler.process(request, response);
            
        } catch (Throwable e) {
            throw new ServletException(e);
        }
        // 만약 뷰 페이지 경로가 존재한다면, RequestDispatcher를 사용하여 해당 뷰 페이지로 포워딩
        // 즉, 요청된 작업의 처리 결과를 클라이언트에게 보여줄 JSP 페이지로 이동하게 된다.
        if (viewPage != null) {
	        RequestDispatcher dispatcher = request.getRequestDispatcher(viewPage);
	        dispatcher.forward(request, response);
        }
    }
}

 

Service

package service;

import java.util.ArrayList;

import dao.BoardDto;

public interface BoardService {
	ArrayList<BoardDto> findAll();
	BoardDto findOne(Long num, boolean incHits);
	void saveOne(BoardDto dto);
	void modifyOne(BoardDto dto);
	void cancelOne(Long num);
	boolean hasArticle(Long num);
}
package service;

import java.util.ArrayList;

import dao.BoardDao;
import dao.BoardDto;

public class BoardServiceImpl implements BoardService {
	
	// 스프링 설정 클래스에서 생성자 생성했으니 생성자 생성 필요 없음
	BoardDao boardDao;
	
	
	// 세터
	public void setBoardDao(BoardDao boardDao) {
		this.boardDao = boardDao;
	}
	
	
	
	// 생성자방식 ( 의존 객체 주입 )
	public BoardServiceImpl(BoardDao boardDao) {
		super();
		// 주입 받은 객체를 필드에 할당
		this.boardDao = boardDao;
	}




	@Override
	public ArrayList<BoardDto> findAll() {
		return boardDao.selectList();
	}

	@Override
	public BoardDto findOne(Long num, boolean incHits) {
		if (incHits) {
			boardDao.updateHits(num);
		}
		return boardDao.selectOne(num, incHits);
	}

	@Override
	public void saveOne(BoardDto dto) {
		boardDao.insertOne(dto);
		
	}

	@Override
	public void modifyOne(BoardDto dto) {
		boardDao.updateOne(dto);
		
	}

	@Override
	public void cancelOne(Long num) {
		boardDao.deleteOne(num);
		
	}



	@Override
	// 게시물 번호를 매개변수로 받아서 해당 번호에 해당하는 게시물이 데이터베이스에 존재하는지 확인
	public boolean hasArticle(Long num) {
		// 주어진 게시물 번호를 가진 게시물을 데이터베이스에서 검색하고 그 결과를 Dto로 반환
		// false로 조회 시 조회수를 증가시키지않게 설정
		BoardDto dto = boardDao.selectOne(num, false);
		if(dto == null) {
			return false;
		}
		//조회 결과(Dto)가 null이 아니라면 해당 게시물이 데이터베이스에 존재하는 것을 의미
		return true;
	}



}

 

1. 핸들러 만들기 

 1) ListHandler

package command;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;

import service.BoardService;

public class ListHandler implements CommandHandler {
	@Autowired
	BoardService boardService;
	@Override
	public String process(HttpServletRequest req, HttpServletResponse res) throws Exception {
	
		// @Autowired 설정 시 밑에 추가 안해줘도 됨
//		BoardService boardService =
//				ControllerUsingURI.ctx.getBean("boardservice", BoardService.class);
			// public static ApplicationContext ctx; 호출
		req.setAttribute("list", boardService.findAll());
		return "/WEB-INF/view/list.jsp";
	}

}
중요한 포인트

@Autowired
BoardService boardService;

설정 시 밑에 추가 안해줘도 됨
		BoardService boardService =
				ControllerUsingURI.ctx.getBean("boardservice", BoardService.class);
			 public static ApplicationContext ctx; 호출

 

 

 

 2) ViewHandler

package command;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;

import dao.BoardDto;
import service.BoardService;

public class ViewHandler implements CommandHandler {
	@Autowired
	BoardService boardService;
	@Override
	public String process(HttpServletRequest req, HttpServletResponse res) throws Exception {
		
		
		long num = Long.parseLong(req.getParameter("num"));
		
		// 방법 1
		BoardDto dto = boardService.findOne(num, true);
		req.setAttribute("dto", dto);
		req.setAttribute("num", num);
		
		// 방법 2
//		req.setAttribute("dto", boardService.findOne(num,true));
		return "/WEB-INF/view/view.jsp";
	}

}

 

 3) WriteHandler

package command;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;

import service.BoardService;

public class WriteHandler implements CommandHandler {
	@Autowired
	BoardService boardService;
	
	@Autowired
	InsertHandler insertHandler;
	
	@Override
	public String process(HttpServletRequest req, HttpServletResponse res) throws Exception {
		
		req.setAttribute("action", "/insert.do");
    	
		
		
		
		return "/WEB-INF/view/write.jsp";
	}
	
	
}

 

2. @Bean 등록

	
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import command.GitHandler;
import command.HelloHandler;
import command.InsertHandler;
import command.ListHandler;
import command.ViewHandler;
import command.WriteHandler;
import dao.BoardDao;
import service.BoardServiceImpl;

@Configuration
public class AppCtx {
	
	@Bean
	public BoardDao boardDao() {
		return new BoardDao();
	}
    
    @Bean // 생성자 방식
	public BoardServiceImpl boardservice() {
		BoardServiceImpl boardservice = new BoardServiceImpl(boardDao());
		return boardservice;
	}
    
    @Bean 
	public ListHandler listHandler() {
		return new ListHandler();
	}
	@Bean 
	public ViewHandler viewHandler() {
		return new ViewHandler();
	}
	
	@Bean
	public WriteHandler writeHandler() {
		return new WriteHandler();
	}

 

3. properties 등록 ( @Bean 메서드 변수 이름으로 등록 ) 

/hello.do=helloHandler
/git.do=gitHandler
/list.do=listHandler
/view.do=viewHandler
/write.do=writeHandler
/insert.do=insertHandler
/login.do=command.LoginHandler
/welcome.do=command.LoginHandler

 

4. JSP 생성

1.  list.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>    

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <style>
        table     { width:680px; text-align:center; }
        th        { background-color:cyan; }
        
        .num      { width: 80px; }
        .title    { width:230px; }
        .writer   { width:100px; }
        .regtime  { width:180px; }
                
        a:link    { text-decoration:none; color:blue; }
        a:visited { text-decoration:none; color:gray; }
        a:hover   { text-decoration:none; color:red;  }
    </style>
</head>
<body>
<div id="result"></div>
<table>
    <tr>
        <th class="num"    >번호    </th>
        <th class="title"  >제목    </th>
        <th class="writer" >작성자  </th>
        <th class="regtime">작성일시</th>
        <th                >조회수  </th>
    </tr>
<c:forEach var="dto" items="${list}">       
        <tr>
            <td>${dto.num}</td>
            <td style="text-align:left;">
                <!-- <a href="#" onclick="ajax(${dto.num})"> -->
                <a href="${pageContext.request.contextPath}/view.do?num=${dto.num}">
                    ${dto.title}
                </a>
            </td>
            <td>${dto.writer}</td>
            <td>${dto.regtime}</td>
            <td>${dto.hits}</td>
        </tr>
</c:forEach>
</table>

<br>
<input type="button" value="글쓰기" onclick="location.href='${pageContext.request.contextPath}/write.do'">
<script>
function ajax(num) {
    var res = document.getElementById("result");
    //var btn = document.getElementById("btn");
    var xhr = new XMLHttpRequest(); 

    xhr.onreadystatechange = function() {
      if (xhr.readyState === 4) {
        if (xhr.status === 200) {
        	console.log(xhr.responseText);
            res.innerHTML = xhr.responseText;
        }
      }
    };

    xhr.open("get", "view2.jsp?num="+num, true);
    xhr.send();
}
</script>
</body>
</html>

 

2. view.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>     

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <style>
        table { width:680px; text-align:center; }
        th    { width:100px; background-color:cyan; }
        td    { text-align:left; border:1px solid gray; }
    </style>
</head>
<body>

<table>
    <tr>
        <th>제목</th>
        <td>${dto.title}</td>
    </tr>
    <tr>
        <th>작성자</th>
        <td>${dto.writer}</td>
    </tr>
    <tr>
        <th>작성일시</th>
        <td>${dto.regtime}</td>
    </tr>
    <tr>
        <th>조회수</th>
        <td>${dto.hits}</td>
    </tr>
    <tr>
        <th>내용</th>
        <td>${dto.content}</td>
    </tr>
</table>

<br>
<input type="button" value="목록보기" onclick="location.href='${pageContext.request.contextPath}/list.do'">
<input type="button" value="수정"
       onclick="location.href='${pageContext.request.contextPath}/write.do?num=${num}'">
<input type="button" value="삭제"
       onclick="location.href='${pageContext.request.contextPath}/delete?num=${num}'">

</body>
</html>

 

3. write.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> 

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <style>
        table { width:680px; text-align:center; }
        th    { width:100px; background-color:cyan; }
        input[type=text], textarea { width:100%; }
    </style>
</head>
<body>

<form method="post" action="${action}">
    <table>
        <tr>
            <th>제목</th>
            <td><input type="text" name="title"  maxlength="80"
                       value="${dto.title}">
            </td>
        </tr>
        <tr>
            <th>작성자</th>
            <td><input type="text" name="writer" maxlength="20"
                       value="${dto.writer}">
            </td>
        </tr>
        <tr>
            <th>내용</th>
            <td><textarea name="content" rows="10">${dto.content}</textarea>
            </td>
        </tr>
    </table>

    <br>
    <input type="submit" value="저장" onclick="location.href='${pageContext.request.contextPath}/insert.do'">
    <input type="button" value="취소" onclick="history.back()">
</form>

</body>
</html>

 

 

서블릿 init 설정 ( 서블릿 만들 때 init 체크 해주면 됨  ) 

 

 

jQuery

 

jQuery를 사용할라면 jQuery 사이트에서 다운로드 클릭 이미지 있는 곳으로 이동 (Google CDN 사용 )

Google CDN 버튼 클릭하면 해당 위치로 이동 3.x스니펫 코드 복사 

 

 

자바스크립트 파일을 로드하기 전에 해당 코드처럼 우선 로드 해야됨 

 <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.0/jquery.min.js"></script>

   <script type="text/javascript">
      $(document).ready(function() {	   
         var resultText = "";
         var $searchEles = $('li');
         console.log($searchEles);
         resultText+="검색된 엘리먼트 개수 : " + $searchEles.length+"\n";
         $searchEles.each(function() {   	  
            resultText+= $(this).text() + "\t";
            $(this).text('빵')
         });
         
         alert($.trim(resultText));
      });
   </script>

 

 

 

addClass

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.7.0/jquery.min.js"></script>
</head>

<style>
    span{font-size: 30pt}
    .redtext {color: red;}
    .italictext { font-style: italic;}
</style>

<body>

   
   
    <span> simple</span>
   
   <script>
		// jQuery 사용 
        $('span').addClass('italictext');
        $('span').addClass('redtext');
        
    </script>

</body>
</html>

jQuery사용 부분을 보면 <span> 부분 선택 후 css 적용 

 

결과를 보면 css 클래스 2개 적용된 모습 

 

 

 

 

셀렉터

 

엘리먼트에 접근해서 스타일 지정하기

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<style>
    .spotlight{background-color: yellow;}
    .redtext {color: red;}
    .largetext {font-size: 30pt;}
    .italictext {font-style: italic;}
</style>

<body>

   <span id="simpletext1">simple</span>
    <div class="simpletext1">jquery</div>
    <span >basic</span>
<div >example</div>  
   
   <script>
    $(document).ready(function(){
        $('span').addClass('redtext');
        debugger;
        $('div').addClass('spotlight');
        $('#simpletext1').addClass('largetext');
        $('.simpletext1').addClass('italictext');
    });
       
    </script>

</body>
</html>

 

 

한 번에 다양한 엘리먼트에 접근하여 개수와 텍스트 얻기

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>한 번에 다양한 엘리먼트에 접근하여 개수와 텍스트 얻기-“selector1, selector2, selectorN”</title>

</head>
<body>


   <span>simple</span>
   <div class='simpletext1'>jQuery</div>
   <div>basic</div>
   <p>example</p>
   <ul>
      <li>떡볶이</li>
      <li>순대</li>
      <li>튀김</li>
   </ul>


   <script type="text/javascript">
      $(document).ready(function() {      
         var resultText = ""; // " 검색된 엘리먼트 개수
         var $searchEles = $('li'); // 배열 비슷 
         console.log($searchEles);
         resultText+="검색된 엘리먼트 개수 : " + $searchEles.length+"\n";
         $searchEles.each(function() {    // each 반복문 비슷  
            resultText+= $(this).text() + "\t";
            // $(this).text('빵') 해당 값 추가시 위에 li무시하고 '빵' 만 출력 
         });
         
         alert($.trim(resultText));
      });
   </script>


</body>
</html>

 

 

확장 객체 집합에서 자손 엘리먼트에 스타일시트 적용하기

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>선택된 jQuery 확장 객체 집합에서 자손 엘리먼트에 스타일시트 적용하기-“ancestor descendant”</title>

<style type="text/css">
   em { font-size: 12pt; line-height: 40pt}
</style>

</head>
<body>

<div>
   <em>Hello!</em>
   <em>jQuery</em>
   <em>forever</em>
</div>
<span>
   <em>Good Bye!</em>
   <em>javascript</em>
</span>


<script type="text/javascript">
   $(document).ready(function() { // 준비된 상태 (ready) 가 되었을 때 적용 콜백함수
     
// 엘리먼트 줄 div 엘리먼트에 포함된 것만 조회하기 위한 셀렉터를 jQuery 함수에 적 용하여 얻은 jQuery 확장 객체 집합에 css() 메소드로 경계선을 그린다.
      $('div em').css('border',  '3pt solid #f00')
                  .css('padding', '7pt 7pt 7pt 7pt');
     
      $('span em').css('border',  '1pt dotted #0f0')
                    .css('padding', '7pt 7pt 7pt 7pt');
     
      console.log("검색된 엘리먼트 개수 : "+ $('div em').length); // 3개
      console.log("검색된 엘리먼트 개수 : "+ $('span em').length); // 2
   });
</script>


</body>
</html>

 

 

 

인접한 자손 엘리먼트를 노드로 추가 ( praent > child )

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>인접한 자손 엘리먼트를 노드로 추가하기</title>

<style type="text/css">
em {
   font-size:20pt; line-height: 20pt;
   margin:20px;   color:blue;  
}

</style>

</head>
<body>
   <p>
      <em> one  </em>
      <em> two  </em>
      <span> <em> three </em> </span>
   </p>
   <div>
      <em> four  </em>
      <span> <em> five  </em> </span>
      <em>six</em>
    </div>
<hr>
   <div>
      <span> ancestor descendant로 검색된 엘리먼트 : </span>
      <span class="result1"></span>
   </div>
   <div>
      <span> parent &gt; child로 검색된 엘리먼트 : </span>
      <span class="result2"></span>
   </div>


<script type="text/javascript">
   $(document).ready(function() {
      $('p em').css('background-color', 'yellow').each(function() {
         $('.result1').append($(this).text()+ "\n");
      });
      $('div > em').css('background-color', 'pink').each(function() {
         $('.result2').append($(this).text()+ "\n");        
      });

      console.log("검색된 엘리먼트 개수 : " + $('p em').length);    
      console.log("검색된 엘리먼트 개수 : " + $('div > em').length);
   });
</script>

</body>
</html>

 

 

 

'프로젝트 기반 자바(JAVA) 응용 SW개발자 취업과정' 카테고리의 다른 글

2023-08-01 53일차  (0) 2023.08.01
2023-07-31 52일차  (0) 2023.07.31
2023-07-27 50일차  (0) 2023.07.27
2023-07-26 49일차  (0) 2023.07.26
2023-07-25 48일차  (0) 2023.07.25

+ Recent posts